(U+51AC): Unify J90-455F.
[chise/xemacs-chise.git-] / 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 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 /* Synched up with: FSF 20.3.  Not in FSF. */
24
25 /* Rewritten by Ben Wing <ben@xemacs.org>. */
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_japanese_jisx0208;
60 Lisp_Object Vcharset_japanese_jisx0208_1990;
61 Lisp_Object Vcharset_korean_ksc5601;
62 Lisp_Object Vcharset_japanese_jisx0212;
63 Lisp_Object Vcharset_chinese_cns11643_1;
64 Lisp_Object Vcharset_chinese_cns11643_2;
65 #ifdef UTF2000
66 Lisp_Object Vcharset_ucs;
67 Lisp_Object Vcharset_ucs_bmp;
68 Lisp_Object Vcharset_ucs_cns;
69 Lisp_Object Vcharset_latin_viscii;
70 Lisp_Object Vcharset_latin_tcvn5712;
71 Lisp_Object Vcharset_latin_viscii_lower;
72 Lisp_Object Vcharset_latin_viscii_upper;
73 Lisp_Object Vcharset_chinese_big5;
74 Lisp_Object Vcharset_ideograph_daikanwa;
75 Lisp_Object Vcharset_mojikyo;
76 Lisp_Object Vcharset_mojikyo_2022_1;
77 Lisp_Object Vcharset_mojikyo_pj_1;
78 Lisp_Object Vcharset_mojikyo_pj_2;
79 Lisp_Object Vcharset_mojikyo_pj_3;
80 Lisp_Object Vcharset_mojikyo_pj_4;
81 Lisp_Object Vcharset_mojikyo_pj_5;
82 Lisp_Object Vcharset_mojikyo_pj_6;
83 Lisp_Object Vcharset_mojikyo_pj_7;
84 Lisp_Object Vcharset_mojikyo_pj_8;
85 Lisp_Object Vcharset_mojikyo_pj_9;
86 Lisp_Object Vcharset_mojikyo_pj_10;
87 Lisp_Object Vcharset_mojikyo_pj_11;
88 Lisp_Object Vcharset_mojikyo_pj_12;
89 Lisp_Object Vcharset_mojikyo_pj_13;
90 Lisp_Object Vcharset_mojikyo_pj_14;
91 Lisp_Object Vcharset_mojikyo_pj_15;
92 Lisp_Object Vcharset_mojikyo_pj_16;
93 Lisp_Object Vcharset_mojikyo_pj_17;
94 Lisp_Object Vcharset_mojikyo_pj_18;
95 Lisp_Object Vcharset_mojikyo_pj_19;
96 Lisp_Object Vcharset_mojikyo_pj_20;
97 Lisp_Object Vcharset_mojikyo_pj_21;
98 Lisp_Object Vcharset_ethiopic_ucs;
99 #endif
100 Lisp_Object Vcharset_chinese_big5_1;
101 Lisp_Object Vcharset_chinese_big5_2;
102
103 #ifdef ENABLE_COMPOSITE_CHARS
104 Lisp_Object Vcharset_composite;
105
106 /* Hash tables for composite chars.  One maps string representing
107    composed chars to their equivalent chars; one goes the
108    other way. */
109 Lisp_Object Vcomposite_char_char2string_hash_table;
110 Lisp_Object Vcomposite_char_string2char_hash_table;
111
112 static int composite_char_row_next;
113 static int composite_char_col_next;
114
115 #endif /* ENABLE_COMPOSITE_CHARS */
116
117 struct charset_lookup *chlook;
118
119 static const struct lrecord_description charset_lookup_description_1[] = {
120   { XD_LISP_OBJECT_ARRAY, offsetof (struct charset_lookup, charset_by_leading_byte),
121 #ifdef UTF2000
122     128+4*128
123 #else
124     128+4*128*2 
125 #endif
126   }, { XD_END }
127 };
128
129 static const struct struct_description charset_lookup_description = {
130   sizeof (struct charset_lookup),
131   charset_lookup_description_1
132 };
133
134 #ifndef UTF2000
135 /* Table of number of bytes in the string representation of a character
136    indexed by the first byte of that representation.
137
138    rep_bytes_by_first_byte(c) is more efficient than the equivalent
139    canonical computation:
140
141    XCHARSET_REP_BYTES (CHARSET_BY_LEADING_BYTE (c)) */
142
143 const Bytecount rep_bytes_by_first_byte[0xA0] =
144 { /* 0x00 - 0x7f are for straight ASCII */
145   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
147   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
148   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
149   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
150   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
151   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
152   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
153   /* 0x80 - 0x8f are for Dimension-1 official charsets */
154 #ifdef CHAR_IS_UCS4
155   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
156 #else
157   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
158 #endif
159   /* 0x90 - 0x9d are for Dimension-2 official charsets */
160   /* 0x9e is for Dimension-1 private charsets */
161   /* 0x9f is for Dimension-2 private charsets */
162   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4
163 };
164 #endif
165
166 #ifdef UTF2000
167
168 #define BT_UINT8_MIN            0
169 #define BT_UINT8_MAX    (UCHAR_MAX - 3)
170 #define BT_UINT8_t      (UCHAR_MAX - 2)
171 #define BT_UINT8_nil    (UCHAR_MAX - 1)
172 #define BT_UINT8_unbound UCHAR_MAX
173
174 INLINE_HEADER int INT_UINT8_P (Lisp_Object obj);
175 INLINE_HEADER int UINT8_VALUE_P (Lisp_Object obj);
176 INLINE_HEADER unsigned char UINT8_ENCODE (Lisp_Object obj);
177 INLINE_HEADER Lisp_Object UINT8_DECODE (unsigned char n);
178 INLINE_HEADER unsigned short UINT8_TO_UINT16 (unsigned char n);
179
180 INLINE_HEADER int
181 INT_UINT8_P (Lisp_Object obj)
182 {
183   if (INTP (obj))
184     {
185       int num = XINT (obj);
186
187       return (BT_UINT8_MIN <= num) && (num <= BT_UINT8_MAX);
188     }
189   else
190     return 0;
191 }
192
193 INLINE_HEADER int
194 UINT8_VALUE_P (Lisp_Object obj)
195 {
196   return EQ (obj, Qunbound)
197     || EQ (obj, Qnil) || EQ (obj, Qt) || INT_UINT8_P (obj);
198 }
199
200 INLINE_HEADER unsigned char
201 UINT8_ENCODE (Lisp_Object obj)
202 {
203   if (EQ (obj, Qunbound))
204     return BT_UINT8_unbound;
205   else if (EQ (obj, Qnil))
206     return BT_UINT8_nil;
207   else if (EQ (obj, Qt))
208     return BT_UINT8_t;
209   else
210     return XINT (obj);
211 }
212
213 INLINE_HEADER Lisp_Object
214 UINT8_DECODE (unsigned char n)
215 {
216   if (n == BT_UINT8_unbound)
217     return Qunbound;
218   else if (n == BT_UINT8_nil)
219     return Qnil;
220   else if (n == BT_UINT8_t)
221     return Qt;
222   else
223     return make_int (n);
224 }
225
226 static Lisp_Object
227 mark_uint8_byte_table (Lisp_Object obj)
228 {
229   return Qnil;
230 }
231
232 static void
233 print_uint8_byte_table (Lisp_Object obj,
234                         Lisp_Object printcharfun, int escapeflag)
235 {
236   Lisp_Uint8_Byte_Table *bte = XUINT8_BYTE_TABLE (obj);
237   int i;
238   struct gcpro gcpro1, gcpro2;
239   GCPRO2 (obj, printcharfun);
240
241   write_c_string ("\n#<uint8-byte-table", printcharfun);
242   for (i = 0; i < 256; i++)
243     {
244       unsigned char n = bte->property[i];
245       if ( (i & 15) == 0 )
246         write_c_string ("\n  ", printcharfun);
247       write_c_string (" ", printcharfun);
248       if (n == BT_UINT8_unbound)
249         write_c_string ("void", printcharfun);
250       else if (n == BT_UINT8_nil)
251         write_c_string ("nil", printcharfun);
252       else if (n == BT_UINT8_t)
253         write_c_string ("t", printcharfun);
254       else
255         {
256           char buf[4];
257
258           sprintf (buf, "%hd", n);
259           write_c_string (buf, printcharfun);
260         }
261     }
262   UNGCPRO;
263   write_c_string (">", printcharfun);
264 }
265
266 static int
267 uint8_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
268 {
269   Lisp_Uint8_Byte_Table *te1 = XUINT8_BYTE_TABLE (obj1);
270   Lisp_Uint8_Byte_Table *te2 = XUINT8_BYTE_TABLE (obj2);
271   int i;
272
273   for (i = 0; i < 256; i++)
274     if (te1->property[i] != te2->property[i])
275       return 0;
276   return 1;
277 }
278
279 static unsigned long
280 uint8_byte_table_hash (Lisp_Object obj, int depth)
281 {
282   Lisp_Uint8_Byte_Table *te = XUINT8_BYTE_TABLE (obj);
283   int i;
284   hashcode_t hash = 0;
285
286   for (i = 0; i < 256; i++)
287     hash = HASH2 (hash, te->property[i]);
288   return hash;
289 }
290
291 DEFINE_LRECORD_IMPLEMENTATION ("uint8-byte-table", uint8_byte_table,
292                                mark_uint8_byte_table,
293                                print_uint8_byte_table,
294                                0, uint8_byte_table_equal,
295                                uint8_byte_table_hash,
296                                0 /* uint8_byte_table_description */,
297                                Lisp_Uint8_Byte_Table);
298
299 static Lisp_Object
300 make_uint8_byte_table (unsigned char initval)
301 {
302   Lisp_Object obj;
303   int i;
304   Lisp_Uint8_Byte_Table *cte;
305
306   cte = alloc_lcrecord_type (Lisp_Uint8_Byte_Table,
307                              &lrecord_uint8_byte_table);
308
309   for (i = 0; i < 256; i++)
310     cte->property[i] = initval;
311
312   XSETUINT8_BYTE_TABLE (obj, cte);
313   return obj;
314 }
315
316 static int
317 uint8_byte_table_same_value_p (Lisp_Object obj)
318 {
319   Lisp_Uint8_Byte_Table *bte = XUINT8_BYTE_TABLE (obj);
320   unsigned char v0 = bte->property[0];
321   int i;
322
323   for (i = 1; i < 256; i++)
324     {
325       if (bte->property[i] != v0)
326         return 0;
327     }
328   return -1;
329 }
330
331
332 #define BT_UINT16_MIN           0
333 #define BT_UINT16_MAX    (USHRT_MAX - 3)
334 #define BT_UINT16_t      (USHRT_MAX - 2)
335 #define BT_UINT16_nil    (USHRT_MAX - 1)
336 #define BT_UINT16_unbound USHRT_MAX
337
338 INLINE_HEADER int INT_UINT16_P (Lisp_Object obj);
339 INLINE_HEADER int UINT16_VALUE_P (Lisp_Object obj);
340 INLINE_HEADER unsigned short UINT16_ENCODE (Lisp_Object obj);
341 INLINE_HEADER Lisp_Object UINT16_DECODE (unsigned short us);
342
343 INLINE_HEADER int
344 INT_UINT16_P (Lisp_Object obj)
345 {
346   if (INTP (obj))
347     {
348       int num = XINT (obj);
349
350       return (BT_UINT16_MIN <= num) && (num <= BT_UINT16_MAX);
351     }
352   else
353     return 0;
354 }
355
356 INLINE_HEADER int
357 UINT16_VALUE_P (Lisp_Object obj)
358 {
359   return EQ (obj, Qunbound)
360     || EQ (obj, Qnil) || EQ (obj, Qt) || INT_UINT16_P (obj);
361 }
362
363 INLINE_HEADER unsigned short
364 UINT16_ENCODE (Lisp_Object obj)
365 {
366   if (EQ (obj, Qunbound))
367     return BT_UINT16_unbound;
368   else if (EQ (obj, Qnil))
369     return BT_UINT16_nil;
370   else if (EQ (obj, Qt))
371     return BT_UINT16_t;
372   else
373     return XINT (obj);
374 }
375
376 INLINE_HEADER Lisp_Object
377 UINT16_DECODE (unsigned short n)
378 {
379   if (n == BT_UINT16_unbound)
380     return Qunbound;
381   else if (n == BT_UINT16_nil)
382     return Qnil;
383   else if (n == BT_UINT16_t)
384     return Qt;
385   else
386     return make_int (n);
387 }
388
389 INLINE_HEADER unsigned short
390 UINT8_TO_UINT16 (unsigned char n)
391 {
392   if (n == BT_UINT8_unbound)
393     return BT_UINT16_unbound;
394   else if (n == BT_UINT8_nil)
395     return BT_UINT16_nil;
396   else if (n == BT_UINT8_t)
397     return BT_UINT16_t;
398   else
399     return n;
400 }
401
402 static Lisp_Object
403 mark_uint16_byte_table (Lisp_Object obj)
404 {
405   return Qnil;
406 }
407
408 static void
409 print_uint16_byte_table (Lisp_Object obj,
410                          Lisp_Object printcharfun, int escapeflag)
411 {
412   Lisp_Uint16_Byte_Table *bte = XUINT16_BYTE_TABLE (obj);
413   int i;
414   struct gcpro gcpro1, gcpro2;
415   GCPRO2 (obj, printcharfun);
416
417   write_c_string ("\n#<uint16-byte-table", printcharfun);
418   for (i = 0; i < 256; i++)
419     {
420       unsigned short n = bte->property[i];
421       if ( (i & 15) == 0 )
422         write_c_string ("\n  ", printcharfun);
423       write_c_string (" ", printcharfun);
424       if (n == BT_UINT16_unbound)
425         write_c_string ("void", printcharfun);
426       else if (n == BT_UINT16_nil)
427         write_c_string ("nil", printcharfun);
428       else if (n == BT_UINT16_t)
429         write_c_string ("t", printcharfun);
430       else
431         {
432           char buf[7];
433
434           sprintf (buf, "%hd", n);
435           write_c_string (buf, printcharfun);
436         }
437     }
438   UNGCPRO;
439   write_c_string (">", printcharfun);
440 }
441
442 static int
443 uint16_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
444 {
445   Lisp_Uint16_Byte_Table *te1 = XUINT16_BYTE_TABLE (obj1);
446   Lisp_Uint16_Byte_Table *te2 = XUINT16_BYTE_TABLE (obj2);
447   int i;
448
449   for (i = 0; i < 256; i++)
450     if (te1->property[i] != te2->property[i])
451       return 0;
452   return 1;
453 }
454
455 static unsigned long
456 uint16_byte_table_hash (Lisp_Object obj, int depth)
457 {
458   Lisp_Uint16_Byte_Table *te = XUINT16_BYTE_TABLE (obj);
459   int i;
460   hashcode_t hash = 0;
461
462   for (i = 0; i < 256; i++)
463     hash = HASH2 (hash, te->property[i]);
464   return hash;
465 }
466
467 DEFINE_LRECORD_IMPLEMENTATION ("uint16-byte-table", uint16_byte_table,
468                                mark_uint16_byte_table,
469                                print_uint16_byte_table,
470                                0, uint16_byte_table_equal,
471                                uint16_byte_table_hash,
472                                0 /* uint16_byte_table_description */,
473                                Lisp_Uint16_Byte_Table);
474
475 static Lisp_Object
476 make_uint16_byte_table (unsigned short initval)
477 {
478   Lisp_Object obj;
479   int i;
480   Lisp_Uint16_Byte_Table *cte;
481
482   cte = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
483                              &lrecord_uint16_byte_table);
484
485   for (i = 0; i < 256; i++)
486     cte->property[i] = initval;
487
488   XSETUINT16_BYTE_TABLE (obj, cte);
489   return obj;
490 }
491
492 static Lisp_Object
493 expand_uint8_byte_table_to_uint16 (Lisp_Object table)
494 {
495   Lisp_Object obj;
496   int i;
497   Lisp_Uint8_Byte_Table* bte = XUINT8_BYTE_TABLE(table);
498   Lisp_Uint16_Byte_Table* cte;
499
500   cte = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
501                              &lrecord_uint16_byte_table);
502   for (i = 0; i < 256; i++)
503     {
504       cte->property[i] = UINT8_TO_UINT16 (bte->property[i]);
505     }
506   XSETUINT16_BYTE_TABLE (obj, cte);
507   return obj;
508 }
509
510 static int
511 uint16_byte_table_same_value_p (Lisp_Object obj)
512 {
513   Lisp_Uint16_Byte_Table *bte = XUINT16_BYTE_TABLE (obj);
514   unsigned short v0 = bte->property[0];
515   int i;
516
517   for (i = 1; i < 256; i++)
518     {
519       if (bte->property[i] != v0)
520         return 0;
521     }
522   return -1;
523 }
524
525
526 static Lisp_Object
527 mark_byte_table (Lisp_Object obj)
528 {
529   Lisp_Byte_Table *cte = XBYTE_TABLE (obj);
530   int i;
531
532   for (i = 0; i < 256; i++)
533     {
534       mark_object (cte->property[i]);
535     }
536   return Qnil;
537 }
538
539 static void
540 print_byte_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
541 {
542   Lisp_Byte_Table *bte = XBYTE_TABLE (obj);
543   int i;
544   struct gcpro gcpro1, gcpro2;
545   GCPRO2 (obj, printcharfun);
546
547   write_c_string ("\n#<byte-table", printcharfun);
548   for (i = 0; i < 256; i++)
549     {
550       Lisp_Object elt = bte->property[i];
551       if ( (i & 15) == 0 )
552         write_c_string ("\n  ", printcharfun);
553       write_c_string (" ", printcharfun);
554       if (EQ (elt, Qunbound))
555         write_c_string ("void", printcharfun);
556       else
557         print_internal (elt, printcharfun, escapeflag);
558     }
559   UNGCPRO;
560   write_c_string (">", printcharfun);
561 }
562
563 static int
564 byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
565 {
566   Lisp_Byte_Table *cte1 = XBYTE_TABLE (obj1);
567   Lisp_Byte_Table *cte2 = XBYTE_TABLE (obj2);
568   int i;
569
570   for (i = 0; i < 256; i++)
571     if (BYTE_TABLE_P (cte1->property[i]))
572       {
573         if (BYTE_TABLE_P (cte2->property[i]))
574           {
575             if (!byte_table_equal (cte1->property[i],
576                                    cte2->property[i], depth + 1))
577               return 0;
578           }
579         else
580           return 0;
581       }
582     else
583       if (!internal_equal (cte1->property[i], cte2->property[i], depth + 1))
584         return 0;
585   return 1;
586 }
587
588 static unsigned long
589 byte_table_hash (Lisp_Object obj, int depth)
590 {
591   Lisp_Byte_Table *cte = XBYTE_TABLE (obj);
592
593   return internal_array_hash (cte->property, 256, depth);
594 }
595
596 static const struct lrecord_description byte_table_description[] = {
597   { XD_LISP_OBJECT_ARRAY, offsetof(Lisp_Byte_Table, property), 256 },
598   { XD_END }
599 };
600
601 DEFINE_LRECORD_IMPLEMENTATION ("byte-table", byte_table,
602                                mark_byte_table,
603                                print_byte_table,
604                                0, byte_table_equal,
605                                byte_table_hash,
606                                byte_table_description,
607                                Lisp_Byte_Table);
608
609 static Lisp_Object
610 make_byte_table (Lisp_Object initval)
611 {
612   Lisp_Object obj;
613   int i;
614   Lisp_Byte_Table *cte;
615
616   cte = alloc_lcrecord_type (Lisp_Byte_Table, &lrecord_byte_table);
617
618   for (i = 0; i < 256; i++)
619     cte->property[i] = initval;
620
621   XSETBYTE_TABLE (obj, cte);
622   return obj;
623 }
624
625 static int
626 byte_table_same_value_p (Lisp_Object obj)
627 {
628   Lisp_Byte_Table *bte = XBYTE_TABLE (obj);
629   Lisp_Object v0 = bte->property[0];
630   int i;
631
632   for (i = 1; i < 256; i++)
633     {
634       if (!internal_equal (bte->property[i], v0, 0))
635         return 0;
636     }
637   return -1;
638 }
639
640
641 Lisp_Object get_byte_table (Lisp_Object table, unsigned char idx);
642 Lisp_Object put_byte_table (Lisp_Object table, unsigned char idx,
643                             Lisp_Object value);
644
645 Lisp_Object
646 get_byte_table (Lisp_Object table, unsigned char idx)
647 {
648   if (UINT8_BYTE_TABLE_P (table))
649     return UINT8_DECODE (XUINT8_BYTE_TABLE(table)->property[idx]);
650   else if (UINT16_BYTE_TABLE_P (table))
651     return UINT16_DECODE (XUINT16_BYTE_TABLE(table)->property[idx]);
652   else if (BYTE_TABLE_P (table))
653     return XBYTE_TABLE(table)->property[idx];
654   else
655     return table;
656 }
657
658 Lisp_Object
659 put_byte_table (Lisp_Object table, unsigned char idx, Lisp_Object value)
660 {
661   if (UINT8_BYTE_TABLE_P (table))
662     {
663       if (UINT8_VALUE_P (value))
664         {
665           XUINT8_BYTE_TABLE(table)->property[idx] = UINT8_ENCODE (value);
666           if (!UINT8_BYTE_TABLE_P (value) &&
667               !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
668               && uint8_byte_table_same_value_p (table))
669             {
670               return value;
671             }
672         }
673       else if (UINT16_VALUE_P (value))
674         {
675           Lisp_Object new = expand_uint8_byte_table_to_uint16 (table);
676
677           XUINT16_BYTE_TABLE(new)->property[idx] = UINT16_ENCODE (value);
678           return new;
679         }
680       else
681         {
682           Lisp_Object new = make_byte_table (Qnil);
683           int i;
684
685           for (i = 0; i < 256; i++)
686             {
687               XBYTE_TABLE(new)->property[i]
688                 = UINT8_DECODE (XUINT8_BYTE_TABLE(table)->property[i]);
689             }
690           XBYTE_TABLE(new)->property[idx] = value;
691           return new;
692         }
693     }
694   else if (UINT16_BYTE_TABLE_P (table))
695     {
696       if (UINT16_VALUE_P (value))
697         {
698           XUINT16_BYTE_TABLE(table)->property[idx] = UINT16_ENCODE (value);
699           if (!UINT8_BYTE_TABLE_P (value) &&
700               !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
701               && uint16_byte_table_same_value_p (table))
702             {
703               return value;
704             }
705         }
706       else
707         {
708           Lisp_Object new = make_byte_table (Qnil);
709           int i;
710
711           for (i = 0; i < 256; i++)
712             {
713               XBYTE_TABLE(new)->property[i]
714                 = UINT16_DECODE (XUINT16_BYTE_TABLE(table)->property[i]);
715             }
716           XBYTE_TABLE(new)->property[idx] = value;
717           return new;
718         }
719     }
720   else if (BYTE_TABLE_P (table))
721     {
722       XBYTE_TABLE(table)->property[idx] = value;
723       if (!UINT8_BYTE_TABLE_P (value) &&
724           !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
725           && byte_table_same_value_p (table))
726         {
727           return value;
728         }
729     }
730   else if (!internal_equal (table, value, 0))
731     {
732       if (UINT8_VALUE_P (table) && UINT8_VALUE_P (value))
733         {
734           table = make_uint8_byte_table (UINT8_ENCODE (table));
735           XUINT8_BYTE_TABLE(table)->property[idx] = UINT8_ENCODE (value);
736         }
737       else if (UINT16_VALUE_P (table) && UINT16_VALUE_P (value))
738         {
739           table = make_uint16_byte_table (UINT16_ENCODE (table));
740           XUINT16_BYTE_TABLE(table)->property[idx] = UINT16_ENCODE (value);
741         }
742       else
743         {
744           table = make_byte_table (table);
745           XBYTE_TABLE(table)->property[idx] = value;
746         }
747     }
748   return table;
749 }
750
751 static Lisp_Object
752 mark_char_id_table (Lisp_Object obj)
753 {
754   Lisp_Char_ID_Table *cte = XCHAR_ID_TABLE (obj);
755
756   return cte->table;
757 }
758
759 static void
760 print_char_id_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
761 {
762   Lisp_Object table = XCHAR_ID_TABLE (obj)->table;
763   int i;
764   struct gcpro gcpro1, gcpro2;
765   GCPRO2 (obj, printcharfun);
766
767   write_c_string ("#<char-id-table ", printcharfun);
768   for (i = 0; i < 256; i++)
769     {
770       Lisp_Object elt = get_byte_table (table, i);
771       if (i != 0) write_c_string ("\n  ", printcharfun);
772       if (EQ (elt, Qunbound))
773         write_c_string ("void", printcharfun);
774       else
775         print_internal (elt, printcharfun, escapeflag);
776     }
777   UNGCPRO;
778   write_c_string (">", printcharfun);
779 }
780
781 static int
782 char_id_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
783 {
784   Lisp_Object table1 = XCHAR_ID_TABLE (obj1)->table;
785   Lisp_Object table2 = XCHAR_ID_TABLE (obj2)->table;
786   int i;
787
788   for (i = 0; i < 256; i++)
789     {
790       if (!internal_equal (get_byte_table (table1, i),
791                           get_byte_table (table2, i), 0))
792         return 0;
793     }
794   return -1;
795 }
796
797 static unsigned long
798 char_id_table_hash (Lisp_Object obj, int depth)
799 {
800   Lisp_Char_ID_Table *cte = XCHAR_ID_TABLE (obj);
801
802   return char_id_table_hash (cte->table, depth + 1);
803 }
804
805 static const struct lrecord_description char_id_table_description[] = {
806   { XD_LISP_OBJECT, offsetof(Lisp_Char_ID_Table, table) },
807   { XD_END }
808 };
809
810 DEFINE_LRECORD_IMPLEMENTATION ("char-id-table", char_id_table,
811                                mark_char_id_table,
812                                print_char_id_table,
813                                0, char_id_table_equal,
814                                char_id_table_hash,
815                                char_id_table_description,
816                                Lisp_Char_ID_Table);
817
818 static Lisp_Object
819 make_char_id_table (Lisp_Object initval)
820 {
821   Lisp_Object obj;
822   Lisp_Char_ID_Table *cte;
823
824   cte = alloc_lcrecord_type (Lisp_Char_ID_Table, &lrecord_char_id_table);
825
826   cte->table = make_byte_table (initval);
827
828   XSETCHAR_ID_TABLE (obj, cte);
829   return obj;
830 }
831
832
833 Lisp_Object
834 get_char_id_table (Emchar ch, Lisp_Object table)
835 {
836   unsigned int code = ch;
837
838   return
839     get_byte_table
840     (get_byte_table
841      (get_byte_table
842       (get_byte_table
843        (XCHAR_ID_TABLE (table)->table,
844         (unsigned char)(code >> 24)),
845        (unsigned char) (code >> 16)),
846       (unsigned char)  (code >> 8)),
847      (unsigned char)    code);
848 }
849
850 void put_char_id_table (Emchar ch, Lisp_Object value, Lisp_Object table);
851 void
852 put_char_id_table (Emchar ch, Lisp_Object value, Lisp_Object table)
853 {
854   unsigned int code = ch;
855   Lisp_Object table1, table2, table3, table4;
856
857   table1 = XCHAR_ID_TABLE (table)->table;
858   table2 = get_byte_table (table1, (unsigned char)(code >> 24));
859   table3 = get_byte_table (table2, (unsigned char)(code >> 16));
860   table4 = get_byte_table (table3, (unsigned char)(code >> 8));
861
862   table4 = put_byte_table (table4, (unsigned char)code,         value);
863   table3 = put_byte_table (table3, (unsigned char)(code >> 8),  table4);
864   table2 = put_byte_table (table2, (unsigned char)(code >> 16), table3);
865   XCHAR_ID_TABLE (table)->table
866     = put_byte_table (table1, (unsigned char)(code >> 24), table2);
867 }
868
869
870 Lisp_Object Vchar_attribute_hash_table;
871 Lisp_Object Vcharacter_composition_table;
872 Lisp_Object Vcharacter_variant_table;
873
874 Lisp_Object Qideograph_daikanwa;
875 Lisp_Object Q_decomposition;
876 Lisp_Object Qucs;
877 Lisp_Object Q_ucs;
878 Lisp_Object Qcompat;
879 Lisp_Object Qisolated;
880 Lisp_Object Qinitial;
881 Lisp_Object Qmedial;
882 Lisp_Object Qfinal;
883 Lisp_Object Qvertical;
884 Lisp_Object QnoBreak;
885 Lisp_Object Qfraction;
886 Lisp_Object Qsuper;
887 Lisp_Object Qsub;
888 Lisp_Object Qcircle;
889 Lisp_Object Qsquare;
890 Lisp_Object Qwide;
891 Lisp_Object Qnarrow;
892 Lisp_Object Qsmall;
893 Lisp_Object Qfont;
894
895 Emchar to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg);
896
897 Lisp_Object put_char_ccs_code_point (Lisp_Object character,
898                                      Lisp_Object ccs, Lisp_Object value);
899 Lisp_Object remove_char_ccs (Lisp_Object character, Lisp_Object ccs);
900
901 Emchar
902 to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg)
903 {
904   if (INTP (v))
905     return XINT (v);
906   if (CHARP (v))
907     return XCHAR (v);
908   else if (EQ (v, Qcompat))
909     return -1;
910   else if (EQ (v, Qisolated))
911     return -2;
912   else if (EQ (v, Qinitial))
913     return -3;
914   else if (EQ (v, Qmedial))
915     return -4;
916   else if (EQ (v, Qfinal))
917     return -5;
918   else if (EQ (v, Qvertical))
919     return -6;
920   else if (EQ (v, QnoBreak))
921     return -7;
922   else if (EQ (v, Qfraction))
923     return -8;
924   else if (EQ (v, Qsuper))
925     return -9;
926   else if (EQ (v, Qsub))
927     return -10;
928   else if (EQ (v, Qcircle))
929     return -11;
930   else if (EQ (v, Qsquare))
931     return -12;
932   else if (EQ (v, Qwide))
933     return -13;
934   else if (EQ (v, Qnarrow))
935     return -14;
936   else if (EQ (v, Qsmall))
937     return -15;
938   else if (EQ (v, Qfont))
939     return -16;
940   else 
941     signal_simple_error (err_msg, err_arg);
942 }
943
944 DEFUN ("get-composite-char", Fget_composite_char, 1, 1, 0, /*
945 Return character corresponding with list.
946 */
947        (list))
948 {
949   Lisp_Object table = Vcharacter_composition_table;
950   Lisp_Object rest = list;
951
952   while (CONSP (rest))
953     {
954       Lisp_Object v = Fcar (rest);
955       Lisp_Object ret;
956       Emchar c = to_char_id (v, "Invalid value for composition", list);
957
958       ret = get_char_id_table (c, table);
959
960       rest = Fcdr (rest);
961       if (NILP (rest))
962         {
963           if (!CHAR_ID_TABLE_P (ret))
964             return ret;
965           else
966             return Qt;
967         }
968       else if (!CONSP (rest))
969         break;
970       else if (CHAR_ID_TABLE_P (ret))
971         table = ret;
972       else
973         signal_simple_error ("Invalid table is found with", list);
974     }
975   signal_simple_error ("Invalid value for composition", list);
976 }
977
978 DEFUN ("char-variants", Fchar_variants, 1, 1, 0, /*
979 Return variants of CHARACTER.
980 */
981        (character))
982 {
983   CHECK_CHAR (character);
984   return Fcopy_list (get_char_id_table (XCHAR (character),
985                                         Vcharacter_variant_table));
986 }
987
988
989 /* We store the char-attributes in hash tables with the names as the
990    key and the actual char-id-table object as the value.  Occasionally
991    we need to use them in a list format.  These routines provide us
992    with that. */
993 struct char_attribute_list_closure
994 {
995   Lisp_Object *char_attribute_list;
996 };
997
998 static int
999 add_char_attribute_to_list_mapper (Lisp_Object key, Lisp_Object value,
1000                                    void *char_attribute_list_closure)
1001 {
1002   /* This function can GC */
1003   struct char_attribute_list_closure *calcl
1004     = (struct char_attribute_list_closure*) char_attribute_list_closure;
1005   Lisp_Object *char_attribute_list = calcl->char_attribute_list;
1006
1007   *char_attribute_list = Fcons (key, *char_attribute_list);
1008   return 0;
1009 }
1010
1011 DEFUN ("char-attribute-list", Fchar_attribute_list, 0, 0, 0, /*
1012 Return the list of all existing character attributes except coded-charsets.
1013 */
1014        ())
1015 {
1016   Lisp_Object char_attribute_list = Qnil;
1017   struct gcpro gcpro1;
1018   struct char_attribute_list_closure char_attribute_list_closure;
1019   
1020   GCPRO1 (char_attribute_list);
1021   char_attribute_list_closure.char_attribute_list = &char_attribute_list;
1022   elisp_maphash (add_char_attribute_to_list_mapper,
1023                  Vchar_attribute_hash_table,
1024                  &char_attribute_list_closure);
1025   UNGCPRO;
1026   return char_attribute_list;
1027 }
1028
1029 DEFUN ("find-char-attribute-table", Ffind_char_attribute_table, 1, 1, 0, /*
1030 Return char-id-table corresponding to ATTRIBUTE.
1031 */
1032        (attribute))
1033 {
1034   return Fgethash (attribute, Vchar_attribute_hash_table, Qnil);
1035 }
1036
1037
1038 /* We store the char-id-tables in hash tables with the attributes as
1039    the key and the actual char-id-table object as the value.  Each
1040    char-id-table stores values of an attribute corresponding with
1041    characters.  Occasionally we need to get attributes of a character
1042    in a association-list format.  These routines provide us with
1043    that. */
1044 struct char_attribute_alist_closure
1045 {
1046   Emchar char_id;
1047   Lisp_Object *char_attribute_alist;
1048 };
1049
1050 static int
1051 add_char_attribute_alist_mapper (Lisp_Object key, Lisp_Object value,
1052                                  void *char_attribute_alist_closure)
1053 {
1054   /* This function can GC */
1055   struct char_attribute_alist_closure *caacl =
1056     (struct char_attribute_alist_closure*) char_attribute_alist_closure;
1057   Lisp_Object ret = get_char_id_table (caacl->char_id, value);
1058   if (!UNBOUNDP (ret))
1059     {
1060       Lisp_Object *char_attribute_alist = caacl->char_attribute_alist;
1061       *char_attribute_alist
1062         = Fcons (Fcons (key, ret), *char_attribute_alist);
1063     }
1064   return 0;
1065 }
1066
1067 DEFUN ("char-attribute-alist", Fchar_attribute_alist, 1, 1, 0, /*
1068 Return the alist of attributes of CHARACTER.
1069 */
1070        (character))
1071 {
1072   Lisp_Object alist = Qnil;
1073   int i;
1074
1075   CHECK_CHAR (character);
1076   {
1077     struct gcpro gcpro1;
1078     struct char_attribute_alist_closure char_attribute_alist_closure;
1079   
1080     GCPRO1 (alist);
1081     char_attribute_alist_closure.char_id = XCHAR (character);
1082     char_attribute_alist_closure.char_attribute_alist = &alist;
1083     elisp_maphash (add_char_attribute_alist_mapper,
1084                    Vchar_attribute_hash_table,
1085                    &char_attribute_alist_closure);
1086     UNGCPRO;
1087   }
1088
1089   for (i = 0; i < countof (chlook->charset_by_leading_byte); i++)
1090     {
1091       Lisp_Object ccs = chlook->charset_by_leading_byte[i];
1092
1093       if (!NILP (ccs))
1094         {
1095           Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
1096           Lisp_Object cpos;
1097
1098           if ( CHAR_ID_TABLE_P (encoding_table)
1099                && INTP (cpos = get_char_id_table (XCHAR (character),
1100                                                   encoding_table)) )
1101             {
1102               alist = Fcons (Fcons (ccs, cpos), alist);
1103             }
1104         }
1105     }
1106   return alist;
1107 }
1108
1109 DEFUN ("get-char-attribute", Fget_char_attribute, 2, 3, 0, /*
1110 Return the value of CHARACTER's ATTRIBUTE.
1111 Return DEFAULT-VALUE if the value is not exist.
1112 */
1113        (character, attribute, default_value))
1114 {
1115   Lisp_Object ccs;
1116
1117   CHECK_CHAR (character);
1118   if (!NILP (ccs = Ffind_charset (attribute)))
1119     {
1120       Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
1121
1122       if (CHAR_ID_TABLE_P (encoding_table))
1123         return get_char_id_table (XCHAR (character), encoding_table);
1124     }
1125   else
1126     {
1127       Lisp_Object table = Fgethash (attribute,
1128                                     Vchar_attribute_hash_table,
1129                                     Qunbound);
1130       if (!UNBOUNDP (table))
1131         {
1132           Lisp_Object ret = get_char_id_table (XCHAR (character), table);
1133           if (!UNBOUNDP (ret))
1134             return ret;
1135         }
1136     }
1137   return default_value;
1138 }
1139
1140 DEFUN ("put-char-attribute", Fput_char_attribute, 3, 3, 0, /*
1141 Store CHARACTER's ATTRIBUTE with VALUE.
1142 */
1143        (character, attribute, value))
1144 {
1145   Lisp_Object ccs;
1146
1147   CHECK_CHAR (character);
1148   ccs = Ffind_charset (attribute);
1149   if (!NILP (ccs))
1150     {
1151       return put_char_ccs_code_point (character, ccs, value);
1152     }
1153   else if (EQ (attribute, Q_decomposition))
1154     {
1155       Lisp_Object seq;
1156
1157       if (!CONSP (value))
1158         signal_simple_error ("Invalid value for ->decomposition",
1159                              value);
1160
1161       if (CONSP (Fcdr (value)))
1162         {
1163           Lisp_Object rest = value;
1164           Lisp_Object table = Vcharacter_composition_table;
1165           size_t len;
1166           int i = 0;
1167
1168           GET_EXTERNAL_LIST_LENGTH (rest, len);
1169           seq = make_vector (len, Qnil);
1170
1171           while (CONSP (rest))
1172             {
1173               Lisp_Object v = Fcar (rest);
1174               Lisp_Object ntable;
1175               Emchar c
1176                 = to_char_id (v, "Invalid value for ->decomposition", value);
1177
1178               if (c < 0)
1179                 XVECTOR_DATA(seq)[i++] = v;
1180               else
1181                 XVECTOR_DATA(seq)[i++] = make_char (c);
1182               rest = Fcdr (rest);
1183               if (!CONSP (rest))
1184                 {
1185                   put_char_id_table (c, character, table);
1186                   break;
1187                 }
1188               else
1189                 {
1190                   ntable = get_char_id_table (c, table);
1191                   if (!CHAR_ID_TABLE_P (ntable))
1192                     {
1193                       ntable = make_char_id_table (Qnil);
1194                       put_char_id_table (c, ntable, table);
1195                     }
1196                   table = ntable;
1197                 }
1198             }
1199         }
1200       else
1201         {
1202           Lisp_Object v = Fcar (value);
1203
1204           if (INTP (v))
1205             {
1206               Emchar c = XINT (v);
1207               Lisp_Object ret
1208                 = get_char_id_table (c, Vcharacter_variant_table);
1209
1210               if (NILP (Fmemq (v, ret)))
1211                 {
1212                   put_char_id_table (c, Fcons (character, ret),
1213                                      Vcharacter_variant_table);
1214                 }
1215             }
1216           seq = make_vector (1, v);
1217         }
1218       value = seq;
1219     }
1220   else if (EQ (attribute, Q_ucs))
1221     {
1222       Lisp_Object ret;
1223       Emchar c;
1224
1225       if (!INTP (value))
1226         signal_simple_error ("Invalid value for ->ucs", value);
1227
1228       c = XINT (value);
1229
1230       ret = get_char_id_table (c, Vcharacter_variant_table);
1231       if (NILP (Fmemq (character, ret)))
1232         {
1233           put_char_id_table (c, Fcons (character, ret),
1234                              Vcharacter_variant_table);
1235         }
1236     }
1237   {
1238     Lisp_Object table = Fgethash (attribute,
1239                                   Vchar_attribute_hash_table,
1240                                   Qnil);
1241
1242     if (NILP (table))
1243       {
1244         table = make_char_id_table (Qunbound);
1245         Fputhash (attribute, table, Vchar_attribute_hash_table);
1246       }
1247     put_char_id_table (XCHAR (character), value, table);
1248     return value;
1249   }
1250 }
1251   
1252 DEFUN ("remove-char-attribute", Fremove_char_attribute, 2, 2, 0, /*
1253 Remove CHARACTER's ATTRIBUTE.
1254 */
1255        (character, attribute))
1256 {
1257   Lisp_Object ccs;
1258
1259   CHECK_CHAR (character);
1260   ccs = Ffind_charset (attribute);
1261   if (!NILP (ccs))
1262     {
1263       return remove_char_ccs (character, ccs);
1264     }
1265   else
1266     {
1267       Lisp_Object table = Fgethash (attribute,
1268                                     Vchar_attribute_hash_table,
1269                                     Qunbound);
1270       if (!UNBOUNDP (table))
1271         {
1272           put_char_id_table (XCHAR (character), Qunbound, table);
1273           return Qt;
1274         }
1275     }
1276   return Qnil;
1277 }
1278
1279 INLINE_HEADER int CHARSET_BYTE_SIZE (Lisp_Charset* cs);
1280 INLINE_HEADER int
1281 CHARSET_BYTE_SIZE (Lisp_Charset* cs)
1282 {
1283   /* ad-hoc method for `ascii' */
1284   if ((CHARSET_CHARS (cs) == 94) &&
1285       (CHARSET_BYTE_OFFSET (cs) != 33))
1286     return 128 - CHARSET_BYTE_OFFSET (cs);
1287   else
1288     return CHARSET_CHARS (cs);
1289 }
1290
1291 #define XCHARSET_BYTE_SIZE(ccs) CHARSET_BYTE_SIZE (XCHARSET (ccs))
1292
1293 int decoding_table_check_elements (Lisp_Object v, int dim, int ccs_len);
1294 int
1295 decoding_table_check_elements (Lisp_Object v, int dim, int ccs_len)
1296 {
1297   int i;
1298
1299   if (XVECTOR_LENGTH (v) > ccs_len)
1300     return -1;
1301
1302   for (i = 0; i < XVECTOR_LENGTH (v); i++)
1303     {
1304       Lisp_Object c = XVECTOR_DATA(v)[i];
1305
1306       if (!NILP (c) && !CHARP (c))
1307         {
1308           if (VECTORP (c))
1309             {
1310               int ret = decoding_table_check_elements (c, dim - 1, ccs_len);
1311               if (ret)
1312                 return ret;
1313             }
1314           else
1315             return -2;
1316         }
1317     }
1318   return 0;
1319 }
1320
1321 INLINE_HEADER void
1322 decoding_table_remove_char (Lisp_Object v, int dim, int byte_offset,
1323                             int code_point);
1324 INLINE_HEADER void
1325 decoding_table_remove_char (Lisp_Object v, int dim, int byte_offset,
1326                             int code_point)
1327 {
1328   int i = -1;
1329
1330   while (dim > 0)
1331     {
1332       Lisp_Object nv;
1333
1334       dim--;
1335       i = ((code_point >> (8 * dim)) & 255) - byte_offset;
1336       nv = XVECTOR_DATA(v)[i];
1337       if (!VECTORP (nv))
1338         break;
1339       v = nv;
1340     }
1341   if (i >= 0)
1342     XVECTOR_DATA(v)[i] = Qnil;
1343 }
1344
1345 INLINE_HEADER void
1346 decoding_table_put_char (Lisp_Object v, int dim, int byte_offset,
1347                          int code_point, Lisp_Object character);
1348 INLINE_HEADER void
1349 decoding_table_put_char (Lisp_Object v, int dim, int byte_offset,
1350                          int code_point, Lisp_Object character)
1351 {
1352   int i = -1;
1353   Lisp_Object nv;
1354   int ccs_len = XVECTOR_LENGTH (v);
1355
1356   while (dim > 0)
1357     {
1358       dim--;
1359       i = ((code_point >> (8 * dim)) & 255) - byte_offset;
1360       nv = XVECTOR_DATA(v)[i];
1361       if (dim > 0)
1362         {
1363           if (!VECTORP (nv))
1364             nv = (XVECTOR_DATA(v)[i] = make_older_vector (ccs_len, Qnil));
1365           v = nv;
1366         }
1367       else
1368         break;
1369     }
1370   XVECTOR_DATA(v)[i] = character;
1371 }
1372
1373 Lisp_Object
1374 put_char_ccs_code_point (Lisp_Object character,
1375                          Lisp_Object ccs, Lisp_Object value)
1376 {
1377   Lisp_Object encoding_table;
1378
1379   if (!EQ (XCHARSET_NAME (ccs), Qucs)
1380       || (XCHAR (character) != XINT (value)))
1381     {
1382       Lisp_Object v = XCHARSET_DECODING_TABLE (ccs);
1383       int dim = XCHARSET_DIMENSION (ccs);
1384       int ccs_len = XCHARSET_BYTE_SIZE (ccs);
1385       int byte_offset = XCHARSET_BYTE_OFFSET (ccs);
1386       int code_point;
1387
1388       if (CONSP (value))
1389         { /* obsolete representation: value must be a list of bytes */
1390           Lisp_Object ret = Fcar (value);
1391           Lisp_Object rest;
1392
1393           if (!INTP (ret))
1394             signal_simple_error ("Invalid value for coded-charset", value);
1395           code_point = XINT (ret);
1396           if (XCHARSET_GRAPHIC (ccs) == 1)
1397             code_point &= 0x7F;
1398           rest = Fcdr (value);
1399           while (!NILP (rest))
1400             {
1401               int j;
1402
1403               if (!CONSP (rest))
1404                 signal_simple_error ("Invalid value for coded-charset",
1405                                      value);
1406               ret = Fcar (rest);
1407               if (!INTP (ret))
1408                 signal_simple_error ("Invalid value for coded-charset",
1409                                      value);
1410               j = XINT (ret);
1411               if (XCHARSET_GRAPHIC (ccs) == 1)
1412                 j &= 0x7F;
1413               code_point = (code_point << 8) | j;
1414               rest = Fcdr (rest);
1415             }
1416           value = make_int (code_point);
1417         }
1418       else if (INTP (value))
1419         {
1420           code_point = XINT (value);
1421           if (XCHARSET_GRAPHIC (ccs) == 1)
1422             {
1423               code_point &= 0x7F7F7F7F;
1424               value = make_int (code_point);
1425             }
1426         }
1427       else
1428         signal_simple_error ("Invalid value for coded-charset", value);
1429
1430       if (VECTORP (v))
1431         {
1432           Lisp_Object cpos = Fget_char_attribute (character, ccs, Qnil);
1433           if (!NILP (cpos))
1434             {
1435               decoding_table_remove_char (v, dim, byte_offset, XINT (cpos));
1436             }
1437         }
1438       else
1439         {
1440           XCHARSET_DECODING_TABLE (ccs)
1441             = v = make_older_vector (ccs_len, Qnil);
1442         }
1443
1444       decoding_table_put_char (v, dim, byte_offset, code_point, character);
1445     }
1446   if (NILP (encoding_table = XCHARSET_ENCODING_TABLE (ccs)))
1447     {
1448       XCHARSET_ENCODING_TABLE (ccs)
1449         = encoding_table = make_char_id_table (Qnil);
1450     }
1451   put_char_id_table (XCHAR (character), value, encoding_table);
1452   return Qt;
1453 }
1454
1455 Lisp_Object
1456 remove_char_ccs (Lisp_Object character, Lisp_Object ccs)
1457 {
1458   Lisp_Object decoding_table = XCHARSET_DECODING_TABLE (ccs);
1459   Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
1460
1461   if (VECTORP (decoding_table))
1462     {
1463       Lisp_Object cpos = Fget_char_attribute (character, ccs, Qnil);
1464
1465       if (!NILP (cpos))
1466         {
1467           decoding_table_remove_char (decoding_table,
1468                                       XCHARSET_DIMENSION (ccs),
1469                                       XCHARSET_BYTE_OFFSET (ccs),
1470                                       XINT (cpos));
1471         }
1472     }
1473   if (CHAR_ID_TABLE_P (encoding_table))
1474     {
1475       put_char_id_table (XCHAR (character), Qnil, encoding_table);
1476     }
1477   return Qt;
1478 }
1479
1480 EXFUN (Fmake_char, 3);
1481 EXFUN (Fdecode_char, 2);
1482
1483 DEFUN ("define-char", Fdefine_char, 1, 1, 0, /*
1484 Store character's ATTRIBUTES.
1485 */
1486        (attributes))
1487 {
1488   Lisp_Object rest = attributes;
1489   Lisp_Object code = Fcdr (Fassq (Qucs, attributes));
1490   Lisp_Object character;
1491 #if 0
1492   Lisp_Object daikanwa = Qnil;
1493 #endif
1494
1495   if (NILP (code))
1496     {
1497       while (CONSP (rest))
1498         {
1499           Lisp_Object cell = Fcar (rest);
1500           Lisp_Object ccs;
1501
1502           if (!LISTP (cell))
1503             signal_simple_error ("Invalid argument", attributes);
1504           if (!NILP (ccs = Ffind_charset (Fcar (cell)))
1505               && ((XCHARSET_FINAL (ccs) != 0) ||
1506                   (XCHARSET_UCS_MAX (ccs) > 0)) )
1507             {
1508               cell = Fcdr (cell);
1509               if (CONSP (cell))
1510                 character = Fmake_char (ccs, Fcar (cell), Fcar (Fcdr (cell)));
1511               else
1512                 character = Fdecode_char (ccs, cell);
1513               goto setup_attributes;
1514             }
1515           rest = Fcdr (rest);
1516         }
1517       if (!NILP (code = Fcdr (Fassq (Q_ucs, attributes))))
1518         {
1519           if (!INTP (code))
1520             signal_simple_error ("Invalid argument", attributes);
1521           else
1522             character = make_char (XINT (code) + 0x100000);
1523           goto setup_attributes;
1524         }
1525       return Qnil;
1526     }
1527   else if (!INTP (code))
1528     signal_simple_error ("Invalid argument", attributes);
1529   else
1530     character = make_char (XINT (code));
1531
1532  setup_attributes:
1533   rest = attributes;
1534   while (CONSP (rest))
1535     {
1536       Lisp_Object cell = Fcar (rest);
1537 #if 0
1538       Lisp_Object key = Fcar (cell);
1539       Lisp_Object value = Fcdr (cell);
1540 #endif
1541
1542       if (!LISTP (cell))
1543         signal_simple_error ("Invalid argument", attributes);
1544
1545 #if 0
1546       if (EQ (key, Qmorohashi_daikanwa))
1547         {
1548           size_t len;
1549           GET_EXTERNAL_LIST_LENGTH (value, len);
1550
1551           if (len == 1)
1552             {
1553               if (NILP (daikanwa))
1554                 daikanwa = Fcdr (Fassq (Qideograph_daikanwa, rest));
1555               if (EQ (Fcar (value), daikanwa))
1556                 goto ignored;
1557             }
1558         }
1559       else if (EQ (key, Qideograph_daikanwa))
1560         daikanwa = value;
1561 #endif
1562
1563       Fput_char_attribute (character, Fcar (cell), Fcdr (cell));
1564 #if 0
1565     ignored:
1566 #endif
1567       rest = Fcdr (rest);
1568     }
1569   return character;
1570 }
1571
1572 Lisp_Object Vutf_2000_version;
1573 #endif
1574
1575 #ifndef UTF2000
1576 int leading_code_private_11;
1577 #endif
1578
1579 Lisp_Object Qcharsetp;
1580
1581 /* Qdoc_string, Qdimension, Qchars defined in general.c */
1582 Lisp_Object Qregistry, Qfinal, Qgraphic;
1583 Lisp_Object Qdirection;
1584 Lisp_Object Qreverse_direction_charset;
1585 Lisp_Object Qleading_byte;
1586 Lisp_Object Qshort_name, Qlong_name;
1587
1588 Lisp_Object Qascii,
1589   Qcontrol_1,
1590   Qlatin_iso8859_1,
1591   Qlatin_iso8859_2,
1592   Qlatin_iso8859_3,
1593   Qlatin_iso8859_4,
1594   Qthai_tis620,
1595   Qgreek_iso8859_7,
1596   Qarabic_iso8859_6,
1597   Qhebrew_iso8859_8,
1598   Qkatakana_jisx0201,
1599   Qlatin_jisx0201,
1600   Qcyrillic_iso8859_5,
1601   Qlatin_iso8859_9,
1602   Qjapanese_jisx0208_1978,
1603   Qchinese_gb2312,
1604   Qjapanese_jisx0208,
1605   Qjapanese_jisx0208_1990,
1606   Qkorean_ksc5601,
1607   Qjapanese_jisx0212,
1608   Qchinese_cns11643_1,
1609   Qchinese_cns11643_2,
1610 #ifdef UTF2000
1611   Qucs_bmp,
1612   Qucs_cns,
1613   Qlatin_viscii,
1614   Qlatin_tcvn5712,
1615   Qlatin_viscii_lower,
1616   Qlatin_viscii_upper,
1617   Qvietnamese_viscii_lower,
1618   Qvietnamese_viscii_upper,
1619   Qchinese_big5,
1620   Qmojikyo,
1621   Qmojikyo_2022_1,
1622   Qmojikyo_pj_1,
1623   Qmojikyo_pj_2,
1624   Qmojikyo_pj_3,
1625   Qmojikyo_pj_4,
1626   Qmojikyo_pj_5,
1627   Qmojikyo_pj_6,
1628   Qmojikyo_pj_7,
1629   Qmojikyo_pj_8,
1630   Qmojikyo_pj_9,
1631   Qmojikyo_pj_10,
1632   Qmojikyo_pj_11,
1633   Qmojikyo_pj_12,
1634   Qmojikyo_pj_13,
1635   Qmojikyo_pj_14,
1636   Qmojikyo_pj_15,
1637   Qmojikyo_pj_16,
1638   Qmojikyo_pj_17,
1639   Qmojikyo_pj_18,
1640   Qmojikyo_pj_19,
1641   Qmojikyo_pj_20,
1642   Qmojikyo_pj_21,
1643   Qethiopic_ucs,
1644 #endif
1645   Qchinese_big5_1,
1646   Qchinese_big5_2,
1647   Qcomposite;
1648
1649 Lisp_Object Ql2r, Qr2l;
1650
1651 Lisp_Object Vcharset_hash_table;
1652
1653 /* Composite characters are characters constructed by overstriking two
1654    or more regular characters.
1655
1656    1) The old Mule implementation involves storing composite characters
1657       in a buffer as a tag followed by all of the actual characters
1658       used to make up the composite character.  I think this is a bad
1659       idea; it greatly complicates code that wants to handle strings
1660       one character at a time because it has to deal with the possibility
1661       of great big ungainly characters.  It's much more reasonable to
1662       simply store an index into a table of composite characters.
1663
1664    2) The current implementation only allows for 16,384 separate
1665       composite characters over the lifetime of the XEmacs process.
1666       This could become a potential problem if the user
1667       edited lots of different files that use composite characters.
1668       Due to FSF bogosity, increasing the number of allowable
1669       composite characters under Mule would decrease the number
1670       of possible faces that can exist.  Mule already has shrunk
1671       this to 2048, and further shrinkage would become uncomfortable.
1672       No such problems exist in XEmacs.
1673
1674       Composite characters could be represented as 0x80 C1 C2 C3,
1675       where each C[1-3] is in the range 0xA0 - 0xFF.  This allows
1676       for slightly under 2^20 (one million) composite characters
1677       over the XEmacs process lifetime, and you only need to
1678       increase the size of a Mule character from 19 to 21 bits.
1679       Or you could use 0x80 C1 C2 C3 C4, allowing for about
1680       85 million (slightly over 2^26) composite characters. */
1681
1682 \f
1683 /************************************************************************/
1684 /*                       Basic Emchar functions                         */
1685 /************************************************************************/
1686
1687 /* Convert a non-ASCII Mule character C into a one-character Mule-encoded
1688    string in STR.  Returns the number of bytes stored.
1689    Do not call this directly.  Use the macro set_charptr_emchar() instead.
1690  */
1691
1692 Bytecount
1693 non_ascii_set_charptr_emchar (Bufbyte *str, Emchar c)
1694 {
1695   Bufbyte *p;
1696 #ifndef UTF2000
1697   Charset_ID lb;
1698   int c1, c2;
1699   Lisp_Object charset;
1700 #endif
1701
1702   p = str;
1703 #ifdef UTF2000
1704   if ( c <= 0x7f )
1705     {
1706       *p++ = c;
1707     }
1708   else if ( c <= 0x7ff )
1709     {
1710       *p++ = (c >> 6) | 0xc0;
1711       *p++ = (c & 0x3f) | 0x80;
1712     }
1713   else if ( c <= 0xffff )
1714     {
1715       *p++ =  (c >> 12) | 0xe0;
1716       *p++ = ((c >>  6) & 0x3f) | 0x80;
1717       *p++ =  (c        & 0x3f) | 0x80;
1718     }
1719   else if ( c <= 0x1fffff )
1720     {
1721       *p++ =  (c >> 18) | 0xf0;
1722       *p++ = ((c >> 12) & 0x3f) | 0x80;
1723       *p++ = ((c >>  6) & 0x3f) | 0x80;
1724       *p++ =  (c        & 0x3f) | 0x80;
1725     }
1726   else if ( c <= 0x3ffffff )
1727     {
1728       *p++ =  (c >> 24) | 0xf8;
1729       *p++ = ((c >> 18) & 0x3f) | 0x80;
1730       *p++ = ((c >> 12) & 0x3f) | 0x80;
1731       *p++ = ((c >>  6) & 0x3f) | 0x80;
1732       *p++ =  (c        & 0x3f) | 0x80;
1733     }
1734   else
1735     {
1736       *p++ =  (c >> 30) | 0xfc;
1737       *p++ = ((c >> 24) & 0x3f) | 0x80;
1738       *p++ = ((c >> 18) & 0x3f) | 0x80;
1739       *p++ = ((c >> 12) & 0x3f) | 0x80;
1740       *p++ = ((c >>  6) & 0x3f) | 0x80;
1741       *p++ =  (c        & 0x3f) | 0x80;
1742     }
1743 #else
1744   BREAKUP_CHAR (c, charset, c1, c2);
1745   lb = CHAR_LEADING_BYTE (c);
1746   if (LEADING_BYTE_PRIVATE_P (lb))
1747     *p++ = PRIVATE_LEADING_BYTE_PREFIX (lb);
1748   *p++ = lb;
1749   if (EQ (charset, Vcharset_control_1))
1750     c1 += 0x20;
1751   *p++ = c1 | 0x80;
1752   if (c2)
1753     *p++ = c2 | 0x80;
1754 #endif
1755   return (p - str);
1756 }
1757
1758 /* Return the first character from a Mule-encoded string in STR,
1759    assuming it's non-ASCII.  Do not call this directly.
1760    Use the macro charptr_emchar() instead. */
1761
1762 Emchar
1763 non_ascii_charptr_emchar (const Bufbyte *str)
1764 {
1765 #ifdef UTF2000
1766   Bufbyte b;
1767   Emchar ch;
1768   int len;
1769
1770   b = *str++;
1771   if ( b >= 0xfc )
1772     {
1773       ch = (b & 0x01);
1774       len = 5;
1775     }
1776   else if ( b >= 0xf8 )
1777     {
1778       ch = b & 0x03;
1779       len = 4;
1780     }
1781   else if ( b >= 0xf0 )
1782     {
1783       ch = b & 0x07;
1784       len = 3;
1785     }
1786   else if ( b >= 0xe0 )
1787     {
1788       ch = b & 0x0f;
1789       len = 2;
1790     }
1791   else if ( b >= 0xc0 )
1792     {
1793       ch = b & 0x1f;
1794       len = 1;
1795     }
1796   else
1797     {
1798       ch = b;
1799       len = 0;
1800     }
1801   for( ; len > 0; len-- )
1802     {
1803       b = *str++;
1804       ch = ( ch << 6 ) | ( b & 0x3f );
1805     }
1806   return ch;
1807 #else
1808   Bufbyte i0 = *str, i1, i2 = 0;
1809   Lisp_Object charset;
1810
1811   if (i0 == LEADING_BYTE_CONTROL_1)
1812     return (Emchar) (*++str - 0x20);
1813
1814   if (LEADING_BYTE_PREFIX_P (i0))
1815     i0 = *++str;
1816
1817   i1 = *++str & 0x7F;
1818
1819   charset = CHARSET_BY_LEADING_BYTE (i0);
1820   if (XCHARSET_DIMENSION (charset) == 2)
1821     i2 = *++str & 0x7F;
1822
1823   return MAKE_CHAR (charset, i1, i2);
1824 #endif
1825 }
1826
1827 /* Return whether CH is a valid Emchar, assuming it's non-ASCII.
1828    Do not call this directly.  Use the macro valid_char_p() instead. */
1829
1830 #ifndef UTF2000
1831 int
1832 non_ascii_valid_char_p (Emchar ch)
1833 {
1834   int f1, f2, f3;
1835
1836   /* Must have only lowest 19 bits set */
1837   if (ch & ~0x7FFFF)
1838     return 0;
1839
1840   f1 = CHAR_FIELD1 (ch);
1841   f2 = CHAR_FIELD2 (ch);
1842   f3 = CHAR_FIELD3 (ch);
1843
1844   if (f1 == 0)
1845     {
1846       Lisp_Object charset;
1847
1848       if (f2 < MIN_CHAR_FIELD2_OFFICIAL ||
1849           (f2 > MAX_CHAR_FIELD2_OFFICIAL && f2 < MIN_CHAR_FIELD2_PRIVATE) ||
1850            f2 > MAX_CHAR_FIELD2_PRIVATE)
1851         return 0;
1852       if (f3 < 0x20)
1853         return 0;
1854
1855       if (f3 != 0x20 && f3 != 0x7F && !(f2 >= MIN_CHAR_FIELD2_PRIVATE &&
1856                                         f2 <= MAX_CHAR_FIELD2_PRIVATE))
1857         return 1;
1858
1859       /*
1860          NOTE: This takes advantage of the fact that
1861          FIELD2_TO_OFFICIAL_LEADING_BYTE and
1862          FIELD2_TO_PRIVATE_LEADING_BYTE are the same.
1863          */
1864       charset = CHARSET_BY_LEADING_BYTE (f2 + FIELD2_TO_OFFICIAL_LEADING_BYTE);
1865       if (EQ (charset, Qnil))
1866         return 0;
1867       return (XCHARSET_CHARS (charset) == 96);
1868     }
1869   else
1870     {
1871       Lisp_Object charset;
1872
1873       if (f1 < MIN_CHAR_FIELD1_OFFICIAL ||
1874           (f1 > MAX_CHAR_FIELD1_OFFICIAL && f1 < MIN_CHAR_FIELD1_PRIVATE) ||
1875           f1 > MAX_CHAR_FIELD1_PRIVATE)
1876         return 0;
1877       if (f2 < 0x20 || f3 < 0x20)
1878         return 0;
1879
1880 #ifdef ENABLE_COMPOSITE_CHARS
1881       if (f1 + FIELD1_TO_OFFICIAL_LEADING_BYTE == LEADING_BYTE_COMPOSITE)
1882         {
1883           if (UNBOUNDP (Fgethash (make_int (ch),
1884                                   Vcomposite_char_char2string_hash_table,
1885                                   Qunbound)))
1886             return 0;
1887           return 1;
1888         }
1889 #endif /* ENABLE_COMPOSITE_CHARS */
1890
1891       if (f2 != 0x20 && f2 != 0x7F && f3 != 0x20 && f3 != 0x7F
1892           && !(f1 >= MIN_CHAR_FIELD1_PRIVATE && f1 <= MAX_CHAR_FIELD1_PRIVATE))
1893         return 1;
1894
1895       if (f1 <= MAX_CHAR_FIELD1_OFFICIAL)
1896         charset =
1897           CHARSET_BY_LEADING_BYTE (f1 + FIELD1_TO_OFFICIAL_LEADING_BYTE);
1898       else
1899         charset =
1900           CHARSET_BY_LEADING_BYTE (f1 + FIELD1_TO_PRIVATE_LEADING_BYTE);
1901
1902       if (EQ (charset, Qnil))
1903         return 0;
1904       return (XCHARSET_CHARS (charset) == 96);
1905     }
1906 }
1907 #endif
1908
1909 \f
1910 /************************************************************************/
1911 /*                       Basic string functions                         */
1912 /************************************************************************/
1913
1914 /* Copy the character pointed to by SRC into DST.  Do not call this
1915    directly.  Use the macro charptr_copy_char() instead.
1916    Return the number of bytes copied.  */
1917
1918 Bytecount
1919 non_ascii_charptr_copy_char (const Bufbyte *src, Bufbyte *dst)
1920 {
1921   unsigned int bytes = REP_BYTES_BY_FIRST_BYTE (*src);
1922   unsigned int i;
1923   for (i = bytes; i; i--, dst++, src++)
1924     *dst = *src;
1925   return bytes;
1926 }
1927
1928 \f
1929 /************************************************************************/
1930 /*                        streams of Emchars                            */
1931 /************************************************************************/
1932
1933 /* Treat a stream as a stream of Emchar's rather than a stream of bytes.
1934    The functions below are not meant to be called directly; use
1935    the macros in insdel.h. */
1936
1937 Emchar
1938 Lstream_get_emchar_1 (Lstream *stream, int ch)
1939 {
1940   Bufbyte str[MAX_EMCHAR_LEN];
1941   Bufbyte *strptr = str;
1942   unsigned int bytes;
1943
1944   str[0] = (Bufbyte) ch;
1945
1946   for (bytes = REP_BYTES_BY_FIRST_BYTE (ch) - 1; bytes; bytes--)
1947     {
1948       int c = Lstream_getc (stream);
1949       bufpos_checking_assert (c >= 0);
1950       *++strptr = (Bufbyte) c;
1951     }
1952   return charptr_emchar (str);
1953 }
1954
1955 int
1956 Lstream_fput_emchar (Lstream *stream, Emchar ch)
1957 {
1958   Bufbyte str[MAX_EMCHAR_LEN];
1959   Bytecount len = set_charptr_emchar (str, ch);
1960   return Lstream_write (stream, str, len);
1961 }
1962
1963 void
1964 Lstream_funget_emchar (Lstream *stream, Emchar ch)
1965 {
1966   Bufbyte str[MAX_EMCHAR_LEN];
1967   Bytecount len = set_charptr_emchar (str, ch);
1968   Lstream_unread (stream, str, len);
1969 }
1970
1971 \f
1972 /************************************************************************/
1973 /*                            charset object                            */
1974 /************************************************************************/
1975
1976 static Lisp_Object
1977 mark_charset (Lisp_Object obj)
1978 {
1979   Lisp_Charset *cs = XCHARSET (obj);
1980
1981   mark_object (cs->short_name);
1982   mark_object (cs->long_name);
1983   mark_object (cs->doc_string);
1984   mark_object (cs->registry);
1985   mark_object (cs->ccl_program);
1986 #ifdef UTF2000
1987   mark_object (cs->encoding_table);
1988   /* mark_object (cs->decoding_table); */
1989 #endif
1990   return cs->name;
1991 }
1992
1993 static void
1994 print_charset (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
1995 {
1996   Lisp_Charset *cs = XCHARSET (obj);
1997   char buf[200];
1998
1999   if (print_readably)
2000     error ("printing unreadable object #<charset %s 0x%x>",
2001            string_data (XSYMBOL (CHARSET_NAME (cs))->name),
2002            cs->header.uid);
2003
2004   write_c_string ("#<charset ", printcharfun);
2005   print_internal (CHARSET_NAME (cs), printcharfun, 0);
2006   write_c_string (" ", printcharfun);
2007   print_internal (CHARSET_SHORT_NAME (cs), printcharfun, 1);
2008   write_c_string (" ", printcharfun);
2009   print_internal (CHARSET_LONG_NAME (cs), printcharfun, 1);
2010   write_c_string (" ", printcharfun);
2011   print_internal (CHARSET_DOC_STRING (cs), printcharfun, 1);
2012   sprintf (buf, " %d^%d %s cols=%d g%d final='%c' reg=",
2013            CHARSET_CHARS (cs),
2014            CHARSET_DIMENSION (cs),
2015            CHARSET_DIRECTION (cs) == CHARSET_LEFT_TO_RIGHT ? "l2r" : "r2l",
2016            CHARSET_COLUMNS (cs),
2017            CHARSET_GRAPHIC (cs),
2018            CHARSET_FINAL (cs));
2019   write_c_string (buf, printcharfun);
2020   print_internal (CHARSET_REGISTRY (cs), printcharfun, 0);
2021   sprintf (buf, " 0x%x>", cs->header.uid);
2022   write_c_string (buf, printcharfun);
2023 }
2024
2025 static const struct lrecord_description charset_description[] = {
2026   { XD_LISP_OBJECT, offsetof (Lisp_Charset, name) },
2027   { XD_LISP_OBJECT, offsetof (Lisp_Charset, doc_string) },
2028   { XD_LISP_OBJECT, offsetof (Lisp_Charset, registry) },
2029   { XD_LISP_OBJECT, offsetof (Lisp_Charset, short_name) },
2030   { XD_LISP_OBJECT, offsetof (Lisp_Charset, long_name) },
2031   { XD_LISP_OBJECT, offsetof (Lisp_Charset, reverse_direction_charset) },
2032   { XD_LISP_OBJECT, offsetof (Lisp_Charset, ccl_program) },
2033 #ifdef UTF2000
2034   { XD_LISP_OBJECT, offsetof (Lisp_Charset, decoding_table) },
2035   { XD_LISP_OBJECT, offsetof (Lisp_Charset, encoding_table) },
2036 #endif
2037   { XD_END }
2038 };
2039
2040 DEFINE_LRECORD_IMPLEMENTATION ("charset", charset,
2041                                mark_charset, print_charset, 0, 0, 0,
2042                                charset_description,
2043                                Lisp_Charset);
2044
2045 /* Make a new charset. */
2046 /* #### SJT Should generic properties be allowed? */
2047 static Lisp_Object
2048 make_charset (Charset_ID id, Lisp_Object name,
2049               unsigned short chars, unsigned char dimension,
2050               unsigned char columns, unsigned char graphic,
2051               Bufbyte final, unsigned char direction, Lisp_Object short_name,
2052               Lisp_Object long_name, Lisp_Object doc,
2053               Lisp_Object reg,
2054               Lisp_Object decoding_table,
2055               Emchar ucs_min, Emchar ucs_max,
2056               Emchar code_offset, unsigned char byte_offset)
2057 {
2058   Lisp_Object obj;
2059   Lisp_Charset *cs = alloc_lcrecord_type (Lisp_Charset, &lrecord_charset);
2060
2061   zero_lcrecord (cs);
2062
2063   XSETCHARSET (obj, cs);
2064
2065   CHARSET_ID            (cs) = id;
2066   CHARSET_NAME          (cs) = name;
2067   CHARSET_SHORT_NAME    (cs) = short_name;
2068   CHARSET_LONG_NAME     (cs) = long_name;
2069   CHARSET_CHARS         (cs) = chars;
2070   CHARSET_DIMENSION     (cs) = dimension;
2071   CHARSET_DIRECTION     (cs) = direction;
2072   CHARSET_COLUMNS       (cs) = columns;
2073   CHARSET_GRAPHIC       (cs) = graphic;
2074   CHARSET_FINAL         (cs) = final;
2075   CHARSET_DOC_STRING    (cs) = doc;
2076   CHARSET_REGISTRY      (cs) = reg;
2077   CHARSET_CCL_PROGRAM   (cs) = Qnil;
2078   CHARSET_REVERSE_DIRECTION_CHARSET (cs) = Qnil;
2079 #ifdef UTF2000
2080   CHARSET_DECODING_TABLE(cs) = Qnil;
2081   CHARSET_ENCODING_TABLE(cs) = Qnil;
2082   CHARSET_UCS_MIN(cs) = ucs_min;
2083   CHARSET_UCS_MAX(cs) = ucs_max;
2084   CHARSET_CODE_OFFSET(cs) = code_offset;
2085   CHARSET_BYTE_OFFSET(cs) = byte_offset;
2086 #endif
2087
2088 #ifndef UTF2000
2089   if (id == LEADING_BYTE_ASCII)
2090     CHARSET_REP_BYTES (cs) = 1;
2091   else if (id < 0xA0)
2092     CHARSET_REP_BYTES (cs) = CHARSET_DIMENSION (cs) + 1;
2093   else
2094     CHARSET_REP_BYTES (cs) = CHARSET_DIMENSION (cs) + 2;
2095 #endif
2096
2097   if (final)
2098     {
2099       /* some charsets do not have final characters.  This includes
2100          ASCII, Control-1, Composite, and the two faux private
2101          charsets. */
2102       unsigned char iso2022_type
2103         = (dimension == 1 ? 0 : 2) + (chars == 94 ? 0 : 1);
2104 #if UTF2000
2105       if (code_offset == 0)
2106         {
2107           assert (NILP (chlook->charset_by_attributes[iso2022_type][final]));
2108           chlook->charset_by_attributes[iso2022_type][final] = obj;
2109         }
2110 #else
2111       assert (NILP
2112               (chlook->charset_by_attributes[iso2022_type][final][direction]));
2113       chlook->charset_by_attributes[iso2022_type][final][direction] = obj;
2114 #endif
2115     }
2116
2117   assert (NILP (chlook->charset_by_leading_byte[id - MIN_LEADING_BYTE]));
2118   chlook->charset_by_leading_byte[id - MIN_LEADING_BYTE] = obj;
2119
2120   /* Some charsets are "faux" and don't have names or really exist at
2121      all except in the leading-byte table. */
2122   if (!NILP (name))
2123     Fputhash (name, obj, Vcharset_hash_table);
2124   return obj;
2125 }
2126
2127 static int
2128 get_unallocated_leading_byte (int dimension)
2129 {
2130   Charset_ID lb;
2131
2132 #ifdef UTF2000
2133   if (chlook->next_allocated_leading_byte > MAX_LEADING_BYTE_PRIVATE)
2134     lb = 0;
2135   else
2136     lb = chlook->next_allocated_leading_byte++;
2137 #else
2138   if (dimension == 1)
2139     {
2140       if (chlook->next_allocated_1_byte_leading_byte > MAX_LEADING_BYTE_PRIVATE_1)
2141         lb = 0;
2142       else
2143         lb = chlook->next_allocated_1_byte_leading_byte++;
2144     }
2145   else
2146     {
2147       if (chlook->next_allocated_2_byte_leading_byte > MAX_LEADING_BYTE_PRIVATE_2)
2148         lb = 0;
2149       else
2150         lb = chlook->next_allocated_2_byte_leading_byte++;
2151     }
2152 #endif
2153
2154   if (!lb)
2155     signal_simple_error
2156       ("No more character sets free for this dimension",
2157        make_int (dimension));
2158
2159   return lb;
2160 }
2161
2162 #ifdef UTF2000
2163 /* Number of Big5 characters which have the same code in 1st byte.  */
2164
2165 #define BIG5_SAME_ROW (0xFF - 0xA1 + 0x7F - 0x40)
2166
2167 Emchar
2168 make_builtin_char (Lisp_Object charset, int c1, int c2)
2169 {
2170   if (XCHARSET_UCS_MAX (charset))
2171     {
2172       Emchar code
2173         = (XCHARSET_DIMENSION (charset) == 1
2174            ?
2175            c1 - XCHARSET_BYTE_OFFSET (charset)
2176            :
2177            (c1 - XCHARSET_BYTE_OFFSET (charset)) * XCHARSET_CHARS (charset)
2178            + c2  - XCHARSET_BYTE_OFFSET (charset))
2179         - XCHARSET_CODE_OFFSET (charset) + XCHARSET_UCS_MIN (charset);
2180       if ((code < XCHARSET_UCS_MIN (charset))
2181           || (XCHARSET_UCS_MAX (charset) < code))
2182         signal_simple_error ("Arguments makes invalid character",
2183                              make_char (code));
2184       return code;
2185     }
2186   else if (XCHARSET_DIMENSION (charset) == 1)
2187     {
2188       switch (XCHARSET_CHARS (charset))
2189         {
2190         case 94:
2191           return MIN_CHAR_94
2192             + (XCHARSET_FINAL (charset) - '0') * 94 + (c1 - 33);
2193         case 96:
2194           return MIN_CHAR_96
2195             + (XCHARSET_FINAL (charset) - '0') * 96 + (c1 - 32);
2196         default:
2197           abort ();
2198         }
2199     }
2200   else
2201     {
2202       if (EQ (charset, Vcharset_chinese_big5))
2203         {
2204           int B1 = c1, B2 = c2;
2205           unsigned int I
2206             = (B1 - 0xA1) * BIG5_SAME_ROW
2207             + B2 - (B2 < 0x7F ? 0x40 : 0x62);
2208
2209           if (B1 < 0xC9)
2210             {
2211               charset = Vcharset_chinese_big5_1;
2212             }
2213           else
2214             {
2215               charset = Vcharset_chinese_big5_2;
2216               I -= (BIG5_SAME_ROW) * (0xC9 - 0xA1);
2217             }
2218           c1 = I / 94 + 33;
2219           c2 = I % 94 + 33;
2220         }
2221       switch (XCHARSET_CHARS (charset))
2222         {
2223         case 94:
2224           return MIN_CHAR_94x94
2225             + (XCHARSET_FINAL (charset) - '0') * 94 * 94
2226             + (c1 - 33) * 94 + (c2 - 33);
2227         case 96:
2228           return MIN_CHAR_96x96
2229             + (XCHARSET_FINAL (charset) - '0') * 96 * 96
2230             + (c1 - 32) * 96 + (c2 - 32);
2231         default:
2232           abort ();
2233         }
2234     }
2235 }
2236
2237 int
2238 range_charset_code_point (Lisp_Object charset, Emchar ch)
2239 {
2240   int d;
2241
2242   if ((XCHARSET_UCS_MIN (charset) <= ch)
2243       && (ch <= XCHARSET_UCS_MAX (charset)))
2244     {
2245       d = ch - XCHARSET_UCS_MIN (charset) + XCHARSET_CODE_OFFSET (charset);
2246
2247       if (XCHARSET_CHARS (charset) == 256)
2248         return d;
2249       else if (XCHARSET_DIMENSION (charset) == 1)
2250         return d + XCHARSET_BYTE_OFFSET (charset);
2251       else if (XCHARSET_DIMENSION (charset) == 2)
2252         return
2253           ((d / XCHARSET_CHARS (charset)
2254             + XCHARSET_BYTE_OFFSET (charset)) << 8)
2255           | (d % XCHARSET_CHARS (charset) + XCHARSET_BYTE_OFFSET (charset));
2256       else if (XCHARSET_DIMENSION (charset) == 3)
2257         return
2258           ((d / (XCHARSET_CHARS (charset) * XCHARSET_CHARS (charset))
2259             + XCHARSET_BYTE_OFFSET (charset)) << 16)
2260           | ((d / XCHARSET_CHARS (charset)
2261               % XCHARSET_CHARS (charset)
2262               + XCHARSET_BYTE_OFFSET (charset)) << 8)
2263           | (d % XCHARSET_CHARS (charset) + XCHARSET_BYTE_OFFSET (charset));
2264       else /* if (XCHARSET_DIMENSION (charset) == 4) */
2265         return
2266           ((d / (XCHARSET_CHARS (charset)
2267                  * XCHARSET_CHARS (charset) * XCHARSET_CHARS (charset))
2268             + XCHARSET_BYTE_OFFSET (charset)) << 24)
2269           | ((d / (XCHARSET_CHARS (charset) * XCHARSET_CHARS (charset))
2270               % XCHARSET_CHARS (charset)
2271               + XCHARSET_BYTE_OFFSET (charset)) << 16)
2272           | ((d / XCHARSET_CHARS (charset) % XCHARSET_CHARS (charset)
2273               + XCHARSET_BYTE_OFFSET (charset)) << 8)
2274           | (d % XCHARSET_CHARS (charset) + XCHARSET_BYTE_OFFSET (charset));
2275     }
2276   else if (XCHARSET_CODE_OFFSET (charset) == 0)
2277     {
2278       if (XCHARSET_DIMENSION (charset) == 1)
2279         {
2280           if (XCHARSET_CHARS (charset) == 94)
2281             {
2282               if (((d = ch - (MIN_CHAR_94
2283                               + (XCHARSET_FINAL (charset) - '0') * 94)) >= 0)
2284                   && (d < 94))
2285                 return d + 33;
2286             }
2287           else if (XCHARSET_CHARS (charset) == 96)
2288             {
2289               if (((d = ch - (MIN_CHAR_96
2290                               + (XCHARSET_FINAL (charset) - '0') * 96)) >= 0)
2291                   && (d < 96))
2292                 return d + 32;
2293             }
2294           else
2295             return -1;
2296         }
2297       else if (XCHARSET_DIMENSION (charset) == 2)
2298         {
2299           if (XCHARSET_CHARS (charset) == 94)
2300             {
2301               if (((d = ch - (MIN_CHAR_94x94
2302                               + (XCHARSET_FINAL (charset) - '0') * 94 * 94))
2303                    >= 0)
2304                   && (d < 94 * 94))
2305                 return (((d / 94) + 33) << 8) | (d % 94 + 33);
2306             }
2307           else if (XCHARSET_CHARS (charset) == 96)
2308             {
2309               if (((d = ch - (MIN_CHAR_96x96
2310                               + (XCHARSET_FINAL (charset) - '0') * 96 * 96))
2311                    >= 0)
2312                   && (d < 96 * 96))
2313                 return (((d / 96) + 32) << 8) | (d % 96 + 32);
2314             }
2315           else
2316             return -1;
2317         }
2318     }
2319   if (EQ (charset, Vcharset_mojikyo_2022_1)
2320       && (MIN_CHAR_MOJIKYO < ch) && (ch < MIN_CHAR_MOJIKYO + 94 * 60 * 94))
2321     {
2322       int m = ch - MIN_CHAR_MOJIKYO - 1;
2323       int byte1 =  m / (94 * 60) + 33;
2324       int byte2 = (m % (94 * 60)) / 94;
2325       int byte3 =  m % 94 + 33;
2326
2327       if (byte2 < 30)
2328         byte2 += 16 + 32;
2329       else
2330         byte2 += 18 + 32;
2331       return (byte1 << 16) | (byte2 << 8) | byte3;
2332     }
2333   return -1;
2334 }
2335
2336 int
2337 encode_builtin_char_1 (Emchar c, Lisp_Object* charset)
2338 {
2339   if (c <= MAX_CHAR_BASIC_LATIN)
2340     {
2341       *charset = Vcharset_ascii;
2342       return c;
2343     }
2344   else if (c < 0xA0)
2345     {
2346       *charset = Vcharset_control_1;
2347       return c & 0x7F;
2348     }
2349   else if (c <= 0xff)
2350     {
2351       *charset = Vcharset_latin_iso8859_1;
2352       return c & 0x7F;
2353     }
2354   /*
2355   else if ((MIN_CHAR_GREEK <= c) && (c <= MAX_CHAR_GREEK))
2356     {
2357       *charset = Vcharset_greek_iso8859_7;
2358       return c - MIN_CHAR_GREEK + 0x20;
2359     }
2360   else if ((MIN_CHAR_CYRILLIC <= c) && (c <= MAX_CHAR_CYRILLIC))
2361     {
2362       *charset = Vcharset_cyrillic_iso8859_5;
2363       return c - MIN_CHAR_CYRILLIC + 0x20;
2364     }
2365   */
2366   else if ((MIN_CHAR_HEBREW <= c) && (c <= MAX_CHAR_HEBREW))
2367     {
2368       *charset = Vcharset_hebrew_iso8859_8;
2369       return c - MIN_CHAR_HEBREW + 0x20;
2370     }
2371   else if ((MIN_CHAR_THAI <= c) && (c <= MAX_CHAR_THAI))
2372     {
2373       *charset = Vcharset_thai_tis620;
2374       return c - MIN_CHAR_THAI + 0x20;
2375     }
2376   /*
2377   else if ((MIN_CHAR_HALFWIDTH_KATAKANA <= c)
2378            && (c <= MAX_CHAR_HALFWIDTH_KATAKANA))
2379     {
2380       return list2 (Vcharset_katakana_jisx0201,
2381                     make_int (c - MIN_CHAR_HALFWIDTH_KATAKANA + 33));
2382     }
2383   */
2384   else if (c <= MAX_CHAR_BMP)
2385     {
2386       *charset = Vcharset_ucs_bmp;
2387       return c;
2388     }
2389   else if (c < MIN_CHAR_DAIKANWA)
2390     {
2391       *charset = Vcharset_ucs;
2392       return c;
2393     }
2394   /*
2395   else if (c <= MAX_CHAR_DAIKANWA)
2396     {
2397       *charset = Vcharset_ideograph_daikanwa;
2398       return c - MIN_CHAR_DAIKANWA;
2399     }
2400   */
2401   else if (c <= MAX_CHAR_MOJIKYO)
2402     {
2403       *charset = Vcharset_mojikyo;
2404       return c - MIN_CHAR_MOJIKYO;
2405     }
2406   else if (c < MIN_CHAR_94)
2407     {
2408       *charset = Vcharset_ucs;
2409       return c;
2410     }
2411   else if (c <= MAX_CHAR_94)
2412     {
2413       *charset = CHARSET_BY_ATTRIBUTES (94, 1,
2414                                         ((c - MIN_CHAR_94) / 94) + '0',
2415                                         CHARSET_LEFT_TO_RIGHT);
2416       if (!NILP (*charset))
2417         return ((c - MIN_CHAR_94) % 94) + 33;
2418       else
2419         {
2420           *charset = Vcharset_ucs;
2421           return c;
2422         }
2423     }
2424   else if (c <= MAX_CHAR_96)
2425     {
2426       *charset = CHARSET_BY_ATTRIBUTES (96, 1,
2427                                         ((c - MIN_CHAR_96) / 96) + '0',
2428                                         CHARSET_LEFT_TO_RIGHT);
2429       if (!NILP (*charset))
2430         return ((c - MIN_CHAR_96) % 96) + 32;
2431       else
2432         {
2433           *charset = Vcharset_ucs;
2434           return c;
2435         }
2436     }
2437   else if (c <= MAX_CHAR_94x94)
2438     {
2439       *charset
2440         = CHARSET_BY_ATTRIBUTES (94, 2,
2441                                  ((c - MIN_CHAR_94x94) / (94 * 94)) + '0',
2442                                  CHARSET_LEFT_TO_RIGHT);
2443       if (!NILP (*charset))
2444         return (((((c - MIN_CHAR_94x94) / 94) % 94) + 33) << 8)
2445           | (((c - MIN_CHAR_94x94) % 94) + 33);
2446       else
2447         {
2448           *charset = Vcharset_ucs;
2449           return c;
2450         }
2451     }
2452   else if (c <= MAX_CHAR_96x96)
2453     {
2454       *charset
2455         = CHARSET_BY_ATTRIBUTES (96, 2,
2456                                  ((c - MIN_CHAR_96x96) / (96 * 96)) + '0',
2457                                  CHARSET_LEFT_TO_RIGHT);
2458       if (!NILP (*charset))
2459         return ((((c - MIN_CHAR_96x96) / 96) % 96) + 32) << 8
2460           | (((c - MIN_CHAR_96x96) % 96) + 32);
2461       else
2462         {
2463           *charset = Vcharset_ucs;
2464           return c;
2465         }
2466     }
2467   else
2468     {
2469       *charset = Vcharset_ucs;
2470       return c;
2471     }
2472 }
2473
2474 Lisp_Object Vdefault_coded_charset_priority_list;
2475 #endif
2476
2477 \f
2478 /************************************************************************/
2479 /*                      Basic charset Lisp functions                    */
2480 /************************************************************************/
2481
2482 DEFUN ("charsetp", Fcharsetp, 1, 1, 0, /*
2483 Return non-nil if OBJECT is a charset.
2484 */
2485        (object))
2486 {
2487   return CHARSETP (object) ? Qt : Qnil;
2488 }
2489
2490 DEFUN ("find-charset", Ffind_charset, 1, 1, 0, /*
2491 Retrieve the charset of the given name.
2492 If CHARSET-OR-NAME is a charset object, it is simply returned.
2493 Otherwise, CHARSET-OR-NAME should be a symbol.  If there is no such charset,
2494 nil is returned.  Otherwise the associated charset object is returned.
2495 */
2496        (charset_or_name))
2497 {
2498   if (CHARSETP (charset_or_name))
2499     return charset_or_name;
2500
2501   CHECK_SYMBOL (charset_or_name);
2502   return Fgethash (charset_or_name, Vcharset_hash_table, Qnil);
2503 }
2504
2505 DEFUN ("get-charset", Fget_charset, 1, 1, 0, /*
2506 Retrieve the charset of the given name.
2507 Same as `find-charset' except an error is signalled if there is no such
2508 charset instead of returning nil.
2509 */
2510        (name))
2511 {
2512   Lisp_Object charset = Ffind_charset (name);
2513
2514   if (NILP (charset))
2515     signal_simple_error ("No such charset", name);
2516   return charset;
2517 }
2518
2519 /* We store the charsets in hash tables with the names as the key and the
2520    actual charset object as the value.  Occasionally we need to use them
2521    in a list format.  These routines provide us with that. */
2522 struct charset_list_closure
2523 {
2524   Lisp_Object *charset_list;
2525 };
2526
2527 static int
2528 add_charset_to_list_mapper (Lisp_Object key, Lisp_Object value,
2529                             void *charset_list_closure)
2530 {
2531   /* This function can GC */
2532   struct charset_list_closure *chcl =
2533     (struct charset_list_closure*) charset_list_closure;
2534   Lisp_Object *charset_list = chcl->charset_list;
2535
2536   *charset_list = Fcons (key /* XCHARSET_NAME (value) */, *charset_list);
2537   return 0;
2538 }
2539
2540 DEFUN ("charset-list", Fcharset_list, 0, 0, 0, /*
2541 Return a list of the names of all defined charsets.
2542 */
2543        ())
2544 {
2545   Lisp_Object charset_list = Qnil;
2546   struct gcpro gcpro1;
2547   struct charset_list_closure charset_list_closure;
2548
2549   GCPRO1 (charset_list);
2550   charset_list_closure.charset_list = &charset_list;
2551   elisp_maphash (add_charset_to_list_mapper, Vcharset_hash_table,
2552                  &charset_list_closure);
2553   UNGCPRO;
2554
2555   return charset_list;
2556 }
2557
2558 DEFUN ("charset-name", Fcharset_name, 1, 1, 0, /*
2559 Return the name of charset CHARSET.
2560 */
2561        (charset))
2562 {
2563   return XCHARSET_NAME (Fget_charset (charset));
2564 }
2565
2566 /* #### SJT Should generic properties be allowed? */
2567 DEFUN ("make-charset", Fmake_charset, 3, 3, 0, /*
2568 Define a new character set.
2569 This function is for use with Mule support.
2570 NAME is a symbol, the name by which the character set is normally referred.
2571 DOC-STRING is a string describing the character set.
2572 PROPS is a property list, describing the specific nature of the
2573 character set.  Recognized properties are:
2574
2575 'short-name     Short version of the charset name (ex: Latin-1)
2576 'long-name      Long version of the charset name (ex: ISO8859-1 (Latin-1))
2577 'registry       A regular expression matching the font registry field for
2578                 this character set.
2579 'dimension      Number of octets used to index a character in this charset.
2580                 Either 1 or 2.  Defaults to 1.
2581 'columns        Number of columns used to display a character in this charset.
2582                 Only used in TTY mode. (Under X, the actual width of a
2583                 character can be derived from the font used to display the
2584                 characters.) If unspecified, defaults to the dimension
2585                 (this is almost always the correct value).
2586 'chars          Number of characters in each dimension (94 or 96).
2587                 Defaults to 94.  Note that if the dimension is 2, the
2588                 character set thus described is 94x94 or 96x96.
2589 'final          Final byte of ISO 2022 escape sequence.  Must be
2590                 supplied.  Each combination of (DIMENSION, CHARS) defines a
2591                 separate namespace for final bytes.  Note that ISO
2592                 2022 restricts the final byte to the range
2593                 0x30 - 0x7E if dimension == 1, and 0x30 - 0x5F if
2594                 dimension == 2.  Note also that final bytes in the range
2595                 0x30 - 0x3F are reserved for user-defined (not official)
2596                 character sets.
2597 'graphic        0 (use left half of font on output) or 1 (use right half
2598                 of font on output).  Defaults to 0.  For example, for
2599                 a font whose registry is ISO8859-1, the left half
2600                 (octets 0x20 - 0x7F) is the `ascii' character set, while
2601                 the right half (octets 0xA0 - 0xFF) is the `latin-1'
2602                 character set.  With 'graphic set to 0, the octets
2603                 will have their high bit cleared; with it set to 1,
2604                 the octets will have their high bit set.
2605 'direction      'l2r (left-to-right) or 'r2l (right-to-left).
2606                 Defaults to 'l2r.
2607 'ccl-program    A compiled CCL program used to convert a character in
2608                 this charset into an index into the font.  This is in
2609                 addition to the 'graphic property.  The CCL program
2610                 is passed the octets of the character, with the high
2611                 bit cleared and set depending upon whether the value
2612                 of the 'graphic property is 0 or 1.
2613 */
2614        (name, doc_string, props))
2615 {
2616   int id, dimension = 1, chars = 94, graphic = 0, final = 0, columns = -1;
2617   int direction = CHARSET_LEFT_TO_RIGHT;
2618   Lisp_Object registry = Qnil;
2619   Lisp_Object charset;
2620   Lisp_Object ccl_program = Qnil;
2621   Lisp_Object short_name = Qnil, long_name = Qnil;
2622   int byte_offset = -1;
2623
2624   CHECK_SYMBOL (name);
2625   if (!NILP (doc_string))
2626     CHECK_STRING (doc_string);
2627
2628   charset = Ffind_charset (name);
2629   if (!NILP (charset))
2630     signal_simple_error ("Cannot redefine existing charset", name);
2631
2632   {
2633     EXTERNAL_PROPERTY_LIST_LOOP_3 (keyword, value, props)
2634       {
2635         if (EQ (keyword, Qshort_name))
2636           {
2637             CHECK_STRING (value);
2638             short_name = value;
2639           }
2640
2641         if (EQ (keyword, Qlong_name))
2642           {
2643             CHECK_STRING (value);
2644             long_name = value;
2645           }
2646
2647         else if (EQ (keyword, Qdimension))
2648           {
2649             CHECK_INT (value);
2650             dimension = XINT (value);
2651             if (dimension < 1 || dimension > 2)
2652               signal_simple_error ("Invalid value for 'dimension", value);
2653           }
2654
2655         else if (EQ (keyword, Qchars))
2656           {
2657             CHECK_INT (value);
2658             chars = XINT (value);
2659             if (chars != 94 && chars != 96)
2660               signal_simple_error ("Invalid value for 'chars", value);
2661           }
2662
2663         else if (EQ (keyword, Qcolumns))
2664           {
2665             CHECK_INT (value);
2666             columns = XINT (value);
2667             if (columns != 1 && columns != 2)
2668               signal_simple_error ("Invalid value for 'columns", value);
2669           }
2670
2671         else if (EQ (keyword, Qgraphic))
2672           {
2673             CHECK_INT (value);
2674             graphic = XINT (value);
2675 #ifdef UTF2000
2676             if (graphic < 0 || graphic > 2)
2677 #else
2678             if (graphic < 0 || graphic > 1)
2679 #endif
2680               signal_simple_error ("Invalid value for 'graphic", value);
2681           }
2682
2683         else if (EQ (keyword, Qregistry))
2684           {
2685             CHECK_STRING (value);
2686             registry = value;
2687           }
2688
2689         else if (EQ (keyword, Qdirection))
2690           {
2691             if (EQ (value, Ql2r))
2692               direction = CHARSET_LEFT_TO_RIGHT;
2693             else if (EQ (value, Qr2l))
2694               direction = CHARSET_RIGHT_TO_LEFT;
2695             else
2696               signal_simple_error ("Invalid value for 'direction", value);
2697           }
2698
2699         else if (EQ (keyword, Qfinal))
2700           {
2701             CHECK_CHAR_COERCE_INT (value);
2702             final = XCHAR (value);
2703             if (final < '0' || final > '~')
2704               signal_simple_error ("Invalid value for 'final", value);
2705           }
2706
2707         else if (EQ (keyword, Qccl_program))
2708           {
2709             struct ccl_program test_ccl;
2710
2711             if (setup_ccl_program (&test_ccl, value) < 0)
2712               signal_simple_error ("Invalid value for 'ccl-program", value);
2713             ccl_program = value;
2714           }
2715
2716         else
2717           signal_simple_error ("Unrecognized property", keyword);
2718       }
2719   }
2720
2721   if (!final)
2722     error ("'final must be specified");
2723   if (dimension == 2 && final > 0x5F)
2724     signal_simple_error
2725       ("Final must be in the range 0x30 - 0x5F for dimension == 2",
2726        make_char (final));
2727
2728   if (!NILP (CHARSET_BY_ATTRIBUTES (chars, dimension, final,
2729                                     CHARSET_LEFT_TO_RIGHT)) ||
2730       !NILP (CHARSET_BY_ATTRIBUTES (chars, dimension, final,
2731                                     CHARSET_RIGHT_TO_LEFT)))
2732     error
2733       ("Character set already defined for this DIMENSION/CHARS/FINAL combo");
2734
2735   id = get_unallocated_leading_byte (dimension);
2736
2737   if (NILP (doc_string))
2738     doc_string = build_string ("");
2739
2740   if (NILP (registry))
2741     registry = build_string ("");
2742
2743   if (NILP (short_name))
2744     XSETSTRING (short_name, XSYMBOL (name)->name);
2745
2746   if (NILP (long_name))
2747     long_name = doc_string;
2748
2749   if (columns == -1)
2750     columns = dimension;
2751
2752   if (byte_offset < 0)
2753     {
2754       if (chars == 94)
2755         byte_offset = 33;
2756       else if (chars == 96)
2757         byte_offset = 32;
2758       else
2759         byte_offset = 0;
2760     }
2761
2762   charset = make_charset (id, name, chars, dimension, columns, graphic,
2763                           final, direction, short_name, long_name,
2764                           doc_string, registry,
2765                           Qnil, 0, 0, 0, byte_offset);
2766   if (!NILP (ccl_program))
2767     XCHARSET_CCL_PROGRAM (charset) = ccl_program;
2768   return charset;
2769 }
2770
2771 DEFUN ("make-reverse-direction-charset", Fmake_reverse_direction_charset,
2772        2, 2, 0, /*
2773 Make a charset equivalent to CHARSET but which goes in the opposite direction.
2774 NEW-NAME is the name of the new charset.  Return the new charset.
2775 */
2776        (charset, new_name))
2777 {
2778   Lisp_Object new_charset = Qnil;
2779   int id, chars, dimension, columns, graphic, final;
2780   int direction;
2781   Lisp_Object registry, doc_string, short_name, long_name;
2782   Lisp_Charset *cs;
2783
2784   charset = Fget_charset (charset);
2785   if (!NILP (XCHARSET_REVERSE_DIRECTION_CHARSET (charset)))
2786     signal_simple_error ("Charset already has reverse-direction charset",
2787                          charset);
2788
2789   CHECK_SYMBOL (new_name);
2790   if (!NILP (Ffind_charset (new_name)))
2791     signal_simple_error ("Cannot redefine existing charset", new_name);
2792
2793   cs = XCHARSET (charset);
2794
2795   chars     = CHARSET_CHARS     (cs);
2796   dimension = CHARSET_DIMENSION (cs);
2797   columns   = CHARSET_COLUMNS   (cs);
2798   id = get_unallocated_leading_byte (dimension);
2799
2800   graphic = CHARSET_GRAPHIC (cs);
2801   final = CHARSET_FINAL (cs);
2802   direction = CHARSET_RIGHT_TO_LEFT;
2803   if (CHARSET_DIRECTION (cs) == CHARSET_RIGHT_TO_LEFT)
2804     direction = CHARSET_LEFT_TO_RIGHT;
2805   doc_string = CHARSET_DOC_STRING (cs);
2806   short_name = CHARSET_SHORT_NAME (cs);
2807   long_name = CHARSET_LONG_NAME (cs);
2808   registry = CHARSET_REGISTRY (cs);
2809
2810   new_charset = make_charset (id, new_name, chars, dimension, columns,
2811                               graphic, final, direction, short_name, long_name,
2812                               doc_string, registry,
2813 #ifdef UTF2000
2814                               CHARSET_DECODING_TABLE(cs),
2815                               CHARSET_UCS_MIN(cs),
2816                               CHARSET_UCS_MAX(cs),
2817                               CHARSET_CODE_OFFSET(cs),
2818                               CHARSET_BYTE_OFFSET(cs)
2819 #else
2820                               Qnil, 0, 0, 0, 0
2821 #endif
2822 );
2823
2824   CHARSET_REVERSE_DIRECTION_CHARSET (cs) = new_charset;
2825   XCHARSET_REVERSE_DIRECTION_CHARSET (new_charset) = charset;
2826
2827   return new_charset;
2828 }
2829
2830 DEFUN ("define-charset-alias", Fdefine_charset_alias, 2, 2, 0, /*
2831 Define symbol ALIAS as an alias for CHARSET.
2832 */
2833        (alias, charset))
2834 {
2835   CHECK_SYMBOL (alias);
2836   charset = Fget_charset (charset);
2837   return Fputhash (alias, charset, Vcharset_hash_table);
2838 }
2839
2840 /* #### Reverse direction charsets not yet implemented.  */
2841 #if 0
2842 DEFUN ("charset-reverse-direction-charset", Fcharset_reverse_direction_charset,
2843        1, 1, 0, /*
2844 Return the reverse-direction charset parallel to CHARSET, if any.
2845 This is the charset with the same properties (in particular, the same
2846 dimension, number of characters per dimension, and final byte) as
2847 CHARSET but whose characters are displayed in the opposite direction.
2848 */
2849        (charset))
2850 {
2851   charset = Fget_charset (charset);
2852   return XCHARSET_REVERSE_DIRECTION_CHARSET (charset);
2853 }
2854 #endif
2855
2856 DEFUN ("charset-from-attributes", Fcharset_from_attributes, 3, 4, 0, /*
2857 Return a charset with the given DIMENSION, CHARS, FINAL, and DIRECTION.
2858 If DIRECTION is omitted, both directions will be checked (left-to-right
2859 will be returned if character sets exist for both directions).
2860 */
2861        (dimension, chars, final, direction))
2862 {
2863   int dm, ch, fi, di = -1;
2864   Lisp_Object obj = Qnil;
2865
2866   CHECK_INT (dimension);
2867   dm = XINT (dimension);
2868   if (dm < 1 || dm > 2)
2869     signal_simple_error ("Invalid value for DIMENSION", dimension);
2870
2871   CHECK_INT (chars);
2872   ch = XINT (chars);
2873   if (ch != 94 && ch != 96)
2874     signal_simple_error ("Invalid value for CHARS", chars);
2875
2876   CHECK_CHAR_COERCE_INT (final);
2877   fi = XCHAR (final);
2878   if (fi < '0' || fi > '~')
2879     signal_simple_error ("Invalid value for FINAL", final);
2880
2881   if (EQ (direction, Ql2r))
2882     di = CHARSET_LEFT_TO_RIGHT;
2883   else if (EQ (direction, Qr2l))
2884     di = CHARSET_RIGHT_TO_LEFT;
2885   else if (!NILP (direction))
2886     signal_simple_error ("Invalid value for DIRECTION", direction);
2887
2888   if (dm == 2 && fi > 0x5F)
2889     signal_simple_error
2890       ("Final must be in the range 0x30 - 0x5F for dimension == 2", final);
2891
2892     if (di == -1)
2893     {
2894       obj = CHARSET_BY_ATTRIBUTES (ch, dm, fi, CHARSET_LEFT_TO_RIGHT);
2895       if (NILP (obj))
2896         obj = CHARSET_BY_ATTRIBUTES (ch, dm, fi, CHARSET_RIGHT_TO_LEFT);
2897     }
2898   else
2899     obj = CHARSET_BY_ATTRIBUTES (ch, dm, fi, di);
2900
2901   if (CHARSETP (obj))
2902     return XCHARSET_NAME (obj);
2903   return obj;
2904 }
2905
2906 DEFUN ("charset-short-name", Fcharset_short_name, 1, 1, 0, /*
2907 Return short name of CHARSET.
2908 */
2909        (charset))
2910 {
2911   return XCHARSET_SHORT_NAME (Fget_charset (charset));
2912 }
2913
2914 DEFUN ("charset-long-name", Fcharset_long_name, 1, 1, 0, /*
2915 Return long name of CHARSET.
2916 */
2917        (charset))
2918 {
2919   return XCHARSET_LONG_NAME (Fget_charset (charset));
2920 }
2921
2922 DEFUN ("charset-description", Fcharset_description, 1, 1, 0, /*
2923 Return description of CHARSET.
2924 */
2925        (charset))
2926 {
2927   return XCHARSET_DOC_STRING (Fget_charset (charset));
2928 }
2929
2930 DEFUN ("charset-dimension", Fcharset_dimension, 1, 1, 0, /*
2931 Return dimension of CHARSET.
2932 */
2933        (charset))
2934 {
2935   return make_int (XCHARSET_DIMENSION (Fget_charset (charset)));
2936 }
2937
2938 DEFUN ("charset-property", Fcharset_property, 2, 2, 0, /*
2939 Return property PROP of CHARSET, a charset object or symbol naming a charset.
2940 Recognized properties are those listed in `make-charset', as well as
2941 'name and 'doc-string.
2942 */
2943        (charset, prop))
2944 {
2945   Lisp_Charset *cs;
2946
2947   charset = Fget_charset (charset);
2948   cs = XCHARSET (charset);
2949
2950   CHECK_SYMBOL (prop);
2951   if (EQ (prop, Qname))        return CHARSET_NAME (cs);
2952   if (EQ (prop, Qshort_name))  return CHARSET_SHORT_NAME (cs);
2953   if (EQ (prop, Qlong_name))   return CHARSET_LONG_NAME (cs);
2954   if (EQ (prop, Qdoc_string))  return CHARSET_DOC_STRING (cs);
2955   if (EQ (prop, Qdimension))   return make_int (CHARSET_DIMENSION (cs));
2956   if (EQ (prop, Qcolumns))     return make_int (CHARSET_COLUMNS (cs));
2957   if (EQ (prop, Qgraphic))     return make_int (CHARSET_GRAPHIC (cs));
2958   if (EQ (prop, Qfinal))       return make_char (CHARSET_FINAL (cs));
2959   if (EQ (prop, Qchars))       return make_int (CHARSET_CHARS (cs));
2960   if (EQ (prop, Qregistry))    return CHARSET_REGISTRY (cs);
2961   if (EQ (prop, Qccl_program)) return CHARSET_CCL_PROGRAM (cs);
2962   if (EQ (prop, Qdirection))
2963     return CHARSET_DIRECTION (cs) == CHARSET_LEFT_TO_RIGHT ? Ql2r : Qr2l;
2964   if (EQ (prop, Qreverse_direction_charset))
2965     {
2966       Lisp_Object obj = CHARSET_REVERSE_DIRECTION_CHARSET (cs);
2967       /* #### Is this translation OK?  If so, error checking sufficient? */
2968       return CHARSETP (obj) ? XCHARSET_NAME (obj) : obj;
2969     }
2970   signal_simple_error ("Unrecognized charset property name", prop);
2971   return Qnil; /* not reached */
2972 }
2973
2974 DEFUN ("charset-id", Fcharset_id, 1, 1, 0, /*
2975 Return charset identification number of CHARSET.
2976 */
2977         (charset))
2978 {
2979   return make_int(XCHARSET_LEADING_BYTE (Fget_charset (charset)));
2980 }
2981
2982 /* #### We need to figure out which properties we really want to
2983    allow to be set. */
2984
2985 DEFUN ("set-charset-ccl-program", Fset_charset_ccl_program, 2, 2, 0, /*
2986 Set the 'ccl-program property of CHARSET to CCL-PROGRAM.
2987 */
2988        (charset, ccl_program))
2989 {
2990   struct ccl_program test_ccl;
2991
2992   charset = Fget_charset (charset);
2993   if (setup_ccl_program (&test_ccl, ccl_program) < 0)
2994     signal_simple_error ("Invalid ccl-program", ccl_program);
2995   XCHARSET_CCL_PROGRAM (charset) = ccl_program;
2996   return Qnil;
2997 }
2998
2999 static void
3000 invalidate_charset_font_caches (Lisp_Object charset)
3001 {
3002   /* Invalidate font cache entries for charset on all devices. */
3003   Lisp_Object devcons, concons, hash_table;
3004   DEVICE_LOOP_NO_BREAK (devcons, concons)
3005     {
3006       struct device *d = XDEVICE (XCAR (devcons));
3007       hash_table = Fgethash (charset, d->charset_font_cache, Qunbound);
3008       if (!UNBOUNDP (hash_table))
3009         Fclrhash (hash_table);
3010     }
3011 }
3012
3013 DEFUN ("set-charset-registry", Fset_charset_registry, 2, 2, 0, /*
3014 Set the 'registry property of CHARSET to REGISTRY.
3015 */
3016        (charset, registry))
3017 {
3018   charset = Fget_charset (charset);
3019   CHECK_STRING (registry);
3020   XCHARSET_REGISTRY (charset) = registry;
3021   invalidate_charset_font_caches (charset);
3022   face_property_was_changed (Vdefault_face, Qfont, Qglobal);
3023   return Qnil;
3024 }
3025
3026 #ifdef UTF2000
3027 DEFUN ("charset-mapping-table", Fcharset_mapping_table, 1, 1, 0, /*
3028 Return mapping-table of CHARSET.
3029 */
3030        (charset))
3031 {
3032   return XCHARSET_DECODING_TABLE (Fget_charset (charset));
3033 }
3034
3035 DEFUN ("set-charset-mapping-table", Fset_charset_mapping_table, 2, 2, 0, /*
3036 Set mapping-table of CHARSET to TABLE.
3037 */
3038        (charset, table))
3039 {
3040   struct Lisp_Charset *cs;
3041   size_t i;
3042   int byte_offset;
3043
3044   charset = Fget_charset (charset);
3045   cs = XCHARSET (charset);
3046
3047   if (NILP (table))
3048     {
3049       if (VECTORP (CHARSET_DECODING_TABLE(cs)))
3050         make_vector_newer (CHARSET_DECODING_TABLE(cs));
3051       CHARSET_DECODING_TABLE(cs) = Qnil;
3052       return table;
3053     }
3054   else if (VECTORP (table))
3055     {
3056       int ccs_len = CHARSET_BYTE_SIZE (cs);
3057       int ret = decoding_table_check_elements (table,
3058                                                CHARSET_DIMENSION (cs),
3059                                                ccs_len);
3060       if (ret)
3061         {
3062           if (ret == -1)
3063             signal_simple_error ("Too big table", table);
3064           else if (ret == -2)
3065             signal_simple_error ("Invalid element is found", table);
3066           else
3067             signal_simple_error ("Something wrong", table);
3068         }
3069       CHARSET_DECODING_TABLE(cs) = Qnil;
3070     }
3071   else
3072     signal_error (Qwrong_type_argument,
3073                   list2 (build_translated_string ("vector-or-nil-p"),
3074                          table));
3075
3076   byte_offset = CHARSET_BYTE_OFFSET (cs);
3077   switch (CHARSET_DIMENSION (cs))
3078     {
3079     case 1:
3080       for (i = 0; i < XVECTOR_LENGTH (table); i++)
3081         {
3082           Lisp_Object c = XVECTOR_DATA(table)[i];
3083
3084           if (CHARP (c))
3085             put_char_ccs_code_point (c, charset,
3086                                      make_int (i + byte_offset));
3087         }
3088       break;
3089     case 2:
3090       for (i = 0; i < XVECTOR_LENGTH (table); i++)
3091         {
3092           Lisp_Object v = XVECTOR_DATA(table)[i];
3093
3094           if (VECTORP (v))
3095             {
3096               size_t j;
3097
3098               for (j = 0; j < XVECTOR_LENGTH (v); j++)
3099                 {
3100                   Lisp_Object c = XVECTOR_DATA(v)[j];
3101
3102                   if (CHARP (c))
3103                     put_char_ccs_code_point
3104                       (c, charset,
3105                        make_int ( ( (i + byte_offset) << 8 )
3106                                   | (j + byte_offset)
3107                                   ) );
3108                 }
3109             }
3110           else if (CHARP (v))
3111             put_char_ccs_code_point (v, charset,
3112                                      make_int (i + byte_offset));
3113         }
3114       break;
3115     }
3116   return table;
3117 }
3118 #endif
3119
3120 \f
3121 /************************************************************************/
3122 /*              Lisp primitives for working with characters             */
3123 /************************************************************************/
3124
3125 #ifdef UTF2000
3126 DEFUN ("decode-char", Fdecode_char, 2, 2, 0, /*
3127 Make a character from CHARSET and code-point CODE.
3128 */
3129        (charset, code))
3130 {
3131   int c;
3132
3133   charset = Fget_charset (charset);
3134   CHECK_INT (code);
3135   c = XINT (code);
3136   if (XCHARSET_GRAPHIC (charset) == 1)
3137     c &= 0x7F7F7F7F;
3138   return make_char (DECODE_CHAR (charset, c));
3139 }
3140
3141 DEFUN ("decode-builtin-char", Fdecode_builtin_char, 2, 2, 0, /*
3142 Make a builtin character from CHARSET and code-point CODE.
3143 */
3144        (charset, code))
3145 {
3146   int c;
3147   int final;
3148
3149   charset = Fget_charset (charset);
3150   CHECK_INT (code);
3151   c = XINT (code);
3152
3153   if ((final = XCHARSET_FINAL (charset)) >= '0')
3154     {
3155       if (XCHARSET_DIMENSION (charset) == 1)
3156         {
3157           switch (XCHARSET_CHARS (charset))
3158             {
3159             case 94:
3160               return
3161                 make_char (MIN_CHAR_94 + (final - '0') * 94
3162                            + ((c & 0x7F) - 33));
3163             case 96:
3164               return
3165                 make_char (MIN_CHAR_96 + (final - '0') * 96
3166                            + ((c & 0x7F) - 32));
3167             default:
3168               return Fdecode_char (charset, code);
3169             }
3170         }
3171       else
3172         {
3173           switch (XCHARSET_CHARS (charset))
3174             {
3175             case 94:
3176               return
3177                 make_char (MIN_CHAR_94x94
3178                            + (final - '0') * 94 * 94
3179                            + (((c >> 8) & 0x7F) - 33) * 94
3180                            + ((c & 0x7F) - 33));
3181             case 96:
3182               return
3183                 make_char (MIN_CHAR_96x96
3184                            + (final - '0') * 96 * 96
3185                            + (((c >> 8) & 0x7F) - 32) * 96
3186                            + ((c & 0x7F) - 32));
3187             default:
3188               return Fdecode_char (charset, code);
3189             }
3190         }
3191     }
3192   else if (XCHARSET_UCS_MAX (charset))
3193     {
3194       Emchar cid
3195         = (XCHARSET_DIMENSION (charset) == 1
3196            ?
3197            c - XCHARSET_BYTE_OFFSET (charset)
3198            :
3199            ((c >> 8) - XCHARSET_BYTE_OFFSET (charset))
3200            * XCHARSET_CHARS (charset)
3201            + (c & 0xFF) - XCHARSET_BYTE_OFFSET (charset))
3202         - XCHARSET_CODE_OFFSET (charset) + XCHARSET_UCS_MIN (charset);
3203       if ((cid < XCHARSET_UCS_MIN (charset))
3204           || (XCHARSET_UCS_MAX (charset) < cid))
3205         return Fdecode_char (charset, code);
3206       return make_char (cid);
3207     }
3208   else
3209     return Fdecode_char (charset, code);
3210 }
3211 #endif
3212
3213 DEFUN ("make-char", Fmake_char, 2, 3, 0, /*
3214 Make a character from CHARSET and octets ARG1 and ARG2.
3215 ARG2 is required only for characters from two-dimensional charsets.
3216 For example, (make-char 'latin-iso8859-2 185) will return the Latin 2
3217 character s with caron.
3218 */
3219        (charset, arg1, arg2))
3220 {
3221   Lisp_Charset *cs;
3222   int a1, a2;
3223   int lowlim, highlim;
3224
3225   charset = Fget_charset (charset);
3226   cs = XCHARSET (charset);
3227
3228   if      (EQ (charset, Vcharset_ascii))     lowlim =  0, highlim = 127;
3229   else if (EQ (charset, Vcharset_control_1)) lowlim =  0, highlim =  31;
3230 #ifdef UTF2000
3231   else if (CHARSET_CHARS (cs) == 256)        lowlim =  0, highlim = 255;
3232 #endif
3233   else if (CHARSET_CHARS (cs) == 94)         lowlim = 33, highlim = 126;
3234   else  /* CHARSET_CHARS (cs) == 96) */      lowlim = 32, highlim = 127;
3235
3236   CHECK_INT (arg1);
3237   /* It is useful (and safe, according to Olivier Galibert) to strip
3238      the 8th bit off ARG1 and ARG2 because it allows programmers to
3239      write (make-char 'latin-iso8859-2 CODE) where code is the actual
3240      Latin 2 code of the character.  */
3241 #ifdef UTF2000
3242   a1 = XINT (arg1);
3243   if (highlim < 128)
3244     a1 &= 0x7f;
3245 #else
3246   a1 = XINT (arg1);
3247 #endif
3248   if (a1 < lowlim || a1 > highlim)
3249     args_out_of_range_3 (arg1, make_int (lowlim), make_int (highlim));
3250
3251   if (CHARSET_DIMENSION (cs) == 1)
3252     {
3253       if (!NILP (arg2))
3254         signal_simple_error
3255           ("Charset is of dimension one; second octet must be nil", arg2);
3256       return make_char (MAKE_CHAR (charset, a1, 0));
3257     }
3258
3259   CHECK_INT (arg2);
3260 #ifdef UTF2000
3261   a2 = XINT (arg2);
3262   if (highlim < 128)
3263     a2 &= 0x7f;
3264 #else
3265   a2 = XINT (arg2) & 0x7f;
3266 #endif
3267   if (a2 < lowlim || a2 > highlim)
3268     args_out_of_range_3 (arg2, make_int (lowlim), make_int (highlim));
3269
3270   return make_char (MAKE_CHAR (charset, a1, a2));
3271 }
3272
3273 DEFUN ("char-charset", Fchar_charset, 1, 1, 0, /*
3274 Return the character set of CHARACTER.
3275 */
3276        (character))
3277 {
3278   CHECK_CHAR_COERCE_INT (character);
3279
3280   return XCHARSET_NAME (CHAR_CHARSET (XCHAR (character)));
3281 }
3282
3283 DEFUN ("char-octet", Fchar_octet, 1, 2, 0, /*
3284 Return the octet numbered N (should be 0 or 1) of CHARACTER.
3285 N defaults to 0 if omitted.
3286 */
3287        (character, n))
3288 {
3289   Lisp_Object charset;
3290   int octet0, octet1;
3291
3292   CHECK_CHAR_COERCE_INT (character);
3293
3294   BREAKUP_CHAR (XCHAR (character), charset, octet0, octet1);
3295
3296   if (NILP (n) || EQ (n, Qzero))
3297     return make_int (octet0);
3298   else if (EQ (n, make_int (1)))
3299     return make_int (octet1);
3300   else
3301     signal_simple_error ("Octet number must be 0 or 1", n);
3302 }
3303
3304 DEFUN ("split-char", Fsplit_char, 1, 1, 0, /*
3305 Return list of charset and one or two position-codes of CHARACTER.
3306 */
3307        (character))
3308 {
3309   /* This function can GC */
3310   struct gcpro gcpro1, gcpro2;
3311   Lisp_Object charset = Qnil;
3312   Lisp_Object rc = Qnil;
3313 #ifdef UTF2000
3314   int code_point;
3315   int dimension;
3316 #else
3317   int c1, c2;
3318 #endif
3319
3320   GCPRO2 (charset, rc);
3321   CHECK_CHAR_COERCE_INT (character);
3322
3323 #ifdef UTF2000
3324   code_point = ENCODE_CHAR (XCHAR (character), charset);
3325   dimension = XCHARSET_DIMENSION (charset);
3326   while (dimension > 0)
3327     {
3328       rc = Fcons (make_int (code_point & 255), rc);
3329       code_point >>= 8;
3330       dimension--;
3331     }
3332   rc = Fcons (XCHARSET_NAME (charset), rc);
3333 #else
3334   BREAKUP_CHAR (XCHAR (character), charset, c1, c2);
3335
3336   if (XCHARSET_DIMENSION (Fget_charset (charset)) == 2)
3337     {
3338       rc = list3 (XCHARSET_NAME (charset), make_int (c1), make_int (c2));
3339     }
3340   else
3341     {
3342       rc = list2 (XCHARSET_NAME (charset), make_int (c1));
3343     }
3344 #endif
3345   UNGCPRO;
3346
3347   return rc;
3348 }
3349
3350 \f
3351 #ifdef ENABLE_COMPOSITE_CHARS
3352 /************************************************************************/
3353 /*                     composite character functions                    */
3354 /************************************************************************/
3355
3356 Emchar
3357 lookup_composite_char (Bufbyte *str, int len)
3358 {
3359   Lisp_Object lispstr = make_string (str, len);
3360   Lisp_Object ch = Fgethash (lispstr,
3361                              Vcomposite_char_string2char_hash_table,
3362                              Qunbound);
3363   Emchar emch;
3364
3365   if (UNBOUNDP (ch))
3366     {
3367       if (composite_char_row_next >= 128)
3368         signal_simple_error ("No more composite chars available", lispstr);
3369       emch = MAKE_CHAR (Vcharset_composite, composite_char_row_next,
3370                         composite_char_col_next);
3371       Fputhash (make_char (emch), lispstr,
3372                 Vcomposite_char_char2string_hash_table);
3373       Fputhash (lispstr, make_char (emch),
3374                 Vcomposite_char_string2char_hash_table);
3375       composite_char_col_next++;
3376       if (composite_char_col_next >= 128)
3377         {
3378           composite_char_col_next = 32;
3379           composite_char_row_next++;
3380         }
3381     }
3382   else
3383     emch = XCHAR (ch);
3384   return emch;
3385 }
3386
3387 Lisp_Object
3388 composite_char_string (Emchar ch)
3389 {
3390   Lisp_Object str = Fgethash (make_char (ch),
3391                               Vcomposite_char_char2string_hash_table,
3392                               Qunbound);
3393   assert (!UNBOUNDP (str));
3394   return str;
3395 }
3396
3397 xxDEFUN ("make-composite-char", Fmake_composite_char, 1, 1, 0, /*
3398 Convert a string into a single composite character.
3399 The character is the result of overstriking all the characters in
3400 the string.
3401 */
3402        (string))
3403 {
3404   CHECK_STRING (string);
3405   return make_char (lookup_composite_char (XSTRING_DATA (string),
3406                                            XSTRING_LENGTH (string)));
3407 }
3408
3409 xxDEFUN ("composite-char-string", Fcomposite_char_string, 1, 1, 0, /*
3410 Return a string of the characters comprising a composite character.
3411 */
3412        (ch))
3413 {
3414   Emchar emch;
3415
3416   CHECK_CHAR (ch);
3417   emch = XCHAR (ch);
3418   if (CHAR_LEADING_BYTE (emch) != LEADING_BYTE_COMPOSITE)
3419     signal_simple_error ("Must be composite char", ch);
3420   return composite_char_string (emch);
3421 }
3422 #endif /* ENABLE_COMPOSITE_CHARS */
3423
3424 \f
3425 /************************************************************************/
3426 /*                            initialization                            */
3427 /************************************************************************/
3428
3429 void
3430 syms_of_mule_charset (void)
3431 {
3432 #ifdef UTF2000
3433   INIT_LRECORD_IMPLEMENTATION (uint8_byte_table);
3434   INIT_LRECORD_IMPLEMENTATION (uint16_byte_table);
3435   INIT_LRECORD_IMPLEMENTATION (byte_table);
3436   INIT_LRECORD_IMPLEMENTATION (char_id_table);
3437 #endif
3438   INIT_LRECORD_IMPLEMENTATION (charset);
3439
3440   DEFSUBR (Fcharsetp);
3441   DEFSUBR (Ffind_charset);
3442   DEFSUBR (Fget_charset);
3443   DEFSUBR (Fcharset_list);
3444   DEFSUBR (Fcharset_name);
3445   DEFSUBR (Fmake_charset);
3446   DEFSUBR (Fmake_reverse_direction_charset);
3447   /*  DEFSUBR (Freverse_direction_charset); */
3448   DEFSUBR (Fdefine_charset_alias);
3449   DEFSUBR (Fcharset_from_attributes);
3450   DEFSUBR (Fcharset_short_name);
3451   DEFSUBR (Fcharset_long_name);
3452   DEFSUBR (Fcharset_description);
3453   DEFSUBR (Fcharset_dimension);
3454   DEFSUBR (Fcharset_property);
3455   DEFSUBR (Fcharset_id);
3456   DEFSUBR (Fset_charset_ccl_program);
3457   DEFSUBR (Fset_charset_registry);
3458 #ifdef UTF2000
3459   DEFSUBR (Fchar_attribute_list);
3460   DEFSUBR (Ffind_char_attribute_table);
3461   DEFSUBR (Fchar_attribute_alist);
3462   DEFSUBR (Fget_char_attribute);
3463   DEFSUBR (Fput_char_attribute);
3464   DEFSUBR (Fremove_char_attribute);
3465   DEFSUBR (Fdefine_char);
3466   DEFSUBR (Fchar_variants);
3467   DEFSUBR (Fget_composite_char);
3468   DEFSUBR (Fcharset_mapping_table);
3469   DEFSUBR (Fset_charset_mapping_table);
3470 #endif
3471
3472 #ifdef UTF2000
3473   DEFSUBR (Fdecode_char);
3474   DEFSUBR (Fdecode_builtin_char);
3475 #endif
3476   DEFSUBR (Fmake_char);
3477   DEFSUBR (Fchar_charset);
3478   DEFSUBR (Fchar_octet);
3479   DEFSUBR (Fsplit_char);
3480
3481 #ifdef ENABLE_COMPOSITE_CHARS
3482   DEFSUBR (Fmake_composite_char);
3483   DEFSUBR (Fcomposite_char_string);
3484 #endif
3485
3486   defsymbol (&Qcharsetp, "charsetp");
3487   defsymbol (&Qregistry, "registry");
3488   defsymbol (&Qfinal, "final");
3489   defsymbol (&Qgraphic, "graphic");
3490   defsymbol (&Qdirection, "direction");
3491   defsymbol (&Qreverse_direction_charset, "reverse-direction-charset");
3492   defsymbol (&Qshort_name, "short-name");
3493   defsymbol (&Qlong_name, "long-name");
3494
3495   defsymbol (&Ql2r, "l2r");
3496   defsymbol (&Qr2l, "r2l");
3497
3498   /* Charsets, compatible with FSF 20.3
3499      Naming convention is Script-Charset[-Edition] */
3500   defsymbol (&Qascii,                   "ascii");
3501   defsymbol (&Qcontrol_1,               "control-1");
3502   defsymbol (&Qlatin_iso8859_1,         "latin-iso8859-1");
3503   defsymbol (&Qlatin_iso8859_2,         "latin-iso8859-2");
3504   defsymbol (&Qlatin_iso8859_3,         "latin-iso8859-3");
3505   defsymbol (&Qlatin_iso8859_4,         "latin-iso8859-4");
3506   defsymbol (&Qthai_tis620,             "thai-tis620");
3507   defsymbol (&Qgreek_iso8859_7,         "greek-iso8859-7");
3508   defsymbol (&Qarabic_iso8859_6,        "arabic-iso8859-6");
3509   defsymbol (&Qhebrew_iso8859_8,        "hebrew-iso8859-8");
3510   defsymbol (&Qkatakana_jisx0201,       "katakana-jisx0201");
3511   defsymbol (&Qlatin_jisx0201,          "latin-jisx0201");
3512   defsymbol (&Qcyrillic_iso8859_5,      "cyrillic-iso8859-5");
3513   defsymbol (&Qlatin_iso8859_9,         "latin-iso8859-9");
3514   defsymbol (&Qjapanese_jisx0208_1978,  "japanese-jisx0208-1978");
3515   defsymbol (&Qchinese_gb2312,          "chinese-gb2312");
3516   defsymbol (&Qjapanese_jisx0208,       "japanese-jisx0208");
3517   defsymbol (&Qjapanese_jisx0208_1990,  "japanese-jisx0208-1990");
3518   defsymbol (&Qkorean_ksc5601,          "korean-ksc5601");
3519   defsymbol (&Qjapanese_jisx0212,       "japanese-jisx0212");
3520   defsymbol (&Qchinese_cns11643_1,      "chinese-cns11643-1");
3521   defsymbol (&Qchinese_cns11643_2,      "chinese-cns11643-2");
3522 #ifdef UTF2000
3523   defsymbol (&Q_ucs,                    "->ucs");
3524   defsymbol (&Q_decomposition,          "->decomposition");
3525   defsymbol (&Qcompat,                  "compat");
3526   defsymbol (&Qisolated,                "isolated");
3527   defsymbol (&Qinitial,                 "initial");
3528   defsymbol (&Qmedial,                  "medial");
3529   defsymbol (&Qfinal,                   "final");
3530   defsymbol (&Qvertical,                "vertical");
3531   defsymbol (&QnoBreak,                 "noBreak");
3532   defsymbol (&Qfraction,                "fraction");
3533   defsymbol (&Qsuper,                   "super");
3534   defsymbol (&Qsub,                     "sub");
3535   defsymbol (&Qcircle,                  "circle");
3536   defsymbol (&Qsquare,                  "square");
3537   defsymbol (&Qwide,                    "wide");
3538   defsymbol (&Qnarrow,                  "narrow");
3539   defsymbol (&Qsmall,                   "small");
3540   defsymbol (&Qfont,                    "font");
3541   defsymbol (&Qucs,                     "ucs");
3542   defsymbol (&Qucs_bmp,                 "ucs-bmp");
3543   defsymbol (&Qucs_cns,                 "ucs-cns");
3544   defsymbol (&Qlatin_viscii,            "latin-viscii");
3545   defsymbol (&Qlatin_tcvn5712,          "latin-tcvn5712");
3546   defsymbol (&Qlatin_viscii_lower,      "latin-viscii-lower");
3547   defsymbol (&Qlatin_viscii_upper,      "latin-viscii-upper");
3548   defsymbol (&Qvietnamese_viscii_lower, "vietnamese-viscii-lower");
3549   defsymbol (&Qvietnamese_viscii_upper, "vietnamese-viscii-upper");
3550   defsymbol (&Qideograph_daikanwa,      "ideograph-daikanwa");
3551   defsymbol (&Qchinese_big5,            "chinese-big5");
3552   defsymbol (&Qmojikyo,                 "mojikyo");
3553   defsymbol (&Qmojikyo_2022_1,          "mojikyo-2022-1");
3554   defsymbol (&Qmojikyo_pj_1,            "mojikyo-pj-1");
3555   defsymbol (&Qmojikyo_pj_2,            "mojikyo-pj-2");
3556   defsymbol (&Qmojikyo_pj_3,            "mojikyo-pj-3");
3557   defsymbol (&Qmojikyo_pj_4,            "mojikyo-pj-4");
3558   defsymbol (&Qmojikyo_pj_5,            "mojikyo-pj-5");
3559   defsymbol (&Qmojikyo_pj_6,            "mojikyo-pj-6");
3560   defsymbol (&Qmojikyo_pj_7,            "mojikyo-pj-7");
3561   defsymbol (&Qmojikyo_pj_8,            "mojikyo-pj-8");
3562   defsymbol (&Qmojikyo_pj_9,            "mojikyo-pj-9");
3563   defsymbol (&Qmojikyo_pj_10,           "mojikyo-pj-10");
3564   defsymbol (&Qmojikyo_pj_11,           "mojikyo-pj-11");
3565   defsymbol (&Qmojikyo_pj_12,           "mojikyo-pj-12");
3566   defsymbol (&Qmojikyo_pj_13,           "mojikyo-pj-13");
3567   defsymbol (&Qmojikyo_pj_14,           "mojikyo-pj-14");
3568   defsymbol (&Qmojikyo_pj_15,           "mojikyo-pj-15");
3569   defsymbol (&Qmojikyo_pj_16,           "mojikyo-pj-16");
3570   defsymbol (&Qmojikyo_pj_17,           "mojikyo-pj-17");
3571   defsymbol (&Qmojikyo_pj_18,           "mojikyo-pj-18");
3572   defsymbol (&Qmojikyo_pj_19,           "mojikyo-pj-19");
3573   defsymbol (&Qmojikyo_pj_20,           "mojikyo-pj-20");
3574   defsymbol (&Qmojikyo_pj_21,           "mojikyo-pj-21");
3575   defsymbol (&Qethiopic_ucs,            "ethiopic-ucs");
3576 #endif
3577   defsymbol (&Qchinese_big5_1,          "chinese-big5-1");
3578   defsymbol (&Qchinese_big5_2,          "chinese-big5-2");
3579
3580   defsymbol (&Qcomposite,               "composite");
3581 }
3582
3583 void
3584 vars_of_mule_charset (void)
3585 {
3586   int i, j;
3587 #ifndef UTF2000
3588   int k;
3589 #endif
3590
3591   chlook = xnew (struct charset_lookup);
3592   dumpstruct (&chlook, &charset_lookup_description);
3593
3594   /* Table of charsets indexed by leading byte. */
3595   for (i = 0; i < countof (chlook->charset_by_leading_byte); i++)
3596     chlook->charset_by_leading_byte[i] = Qnil;
3597
3598 #ifdef UTF2000
3599   /* Table of charsets indexed by type/final-byte. */
3600   for (i = 0; i < countof (chlook->charset_by_attributes); i++)
3601     for (j = 0; j < countof (chlook->charset_by_attributes[0]); j++)
3602       chlook->charset_by_attributes[i][j] = Qnil;
3603 #else
3604   /* Table of charsets indexed by type/final-byte/direction. */
3605   for (i = 0; i < countof (chlook->charset_by_attributes); i++)
3606     for (j = 0; j < countof (chlook->charset_by_attributes[0]); j++)
3607       for (k = 0; k < countof (chlook->charset_by_attributes[0][0]); k++)
3608         chlook->charset_by_attributes[i][j][k] = Qnil;
3609 #endif
3610
3611 #ifdef UTF2000
3612   chlook->next_allocated_leading_byte = MIN_LEADING_BYTE_PRIVATE;
3613 #else
3614   chlook->next_allocated_1_byte_leading_byte = MIN_LEADING_BYTE_PRIVATE_1;
3615   chlook->next_allocated_2_byte_leading_byte = MIN_LEADING_BYTE_PRIVATE_2;
3616 #endif
3617
3618 #ifndef UTF2000
3619   leading_code_private_11 = PRE_LEADING_BYTE_PRIVATE_1;
3620   DEFVAR_INT ("leading-code-private-11", &leading_code_private_11 /*
3621 Leading-code of private TYPE9N charset of column-width 1.
3622 */ );
3623   leading_code_private_11 = PRE_LEADING_BYTE_PRIVATE_1;
3624 #endif
3625
3626 #ifdef UTF2000
3627   Vutf_2000_version = build_string("0.17 (Hōryūji)");
3628   DEFVAR_LISP ("utf-2000-version", &Vutf_2000_version /*
3629 Version number of UTF-2000.
3630 */ );
3631
3632   staticpro (&Vcharacter_composition_table);
3633   Vcharacter_composition_table = make_char_id_table (Qnil);
3634
3635   staticpro (&Vcharacter_variant_table);
3636   Vcharacter_variant_table = make_char_id_table (Qnil);
3637
3638   Vdefault_coded_charset_priority_list = Qnil;
3639   DEFVAR_LISP ("default-coded-charset-priority-list",
3640                &Vdefault_coded_charset_priority_list /*
3641 Default order of preferred coded-character-sets.
3642 */ );
3643 #endif
3644 }
3645
3646 void
3647 complex_vars_of_mule_charset (void)
3648 {
3649   staticpro (&Vcharset_hash_table);
3650   Vcharset_hash_table =
3651     make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
3652
3653   /* Predefined character sets.  We store them into variables for
3654      ease of access. */
3655
3656 #ifdef UTF2000
3657   staticpro (&Vchar_attribute_hash_table);
3658   Vchar_attribute_hash_table
3659     = make_lisp_hash_table (16, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
3660
3661   staticpro (&Vcharset_ucs);
3662   Vcharset_ucs =
3663     make_charset (LEADING_BYTE_UCS, Qucs, 256, 4,
3664                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
3665                   build_string ("UCS"),
3666                   build_string ("UCS"),
3667                   build_string ("ISO/IEC 10646"),
3668                   build_string (""),
3669                   Qnil, 0, 0xFFFFFFF, 0, 0);
3670   staticpro (&Vcharset_ucs_bmp);
3671   Vcharset_ucs_bmp =
3672     make_charset (LEADING_BYTE_UCS_BMP, Qucs_bmp, 256, 2,
3673                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
3674                   build_string ("BMP"),
3675                   build_string ("BMP"),
3676                   build_string ("ISO/IEC 10646 Group 0 Plane 0 (BMP)"),
3677                   build_string ("\\(ISO10646.*-1\\|UNICODE[23]?-0\\)"),
3678                   Qnil, 0, 0xFFFF, 0, 0);
3679   staticpro (&Vcharset_ucs_cns);
3680   Vcharset_ucs_cns =
3681     make_charset (LEADING_BYTE_UCS_CNS, Qucs_cns, 256, 4,
3682                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
3683                   build_string ("UCS for CNS"),
3684                   build_string ("UCS for CNS 11643"),
3685                   build_string ("ISO/IEC 10646 for CNS 11643"),
3686                   build_string (""),
3687                   Qnil, 0, 0xFFFFFFF, 0, 0);
3688 #else
3689 # define MIN_CHAR_THAI 0
3690 # define MAX_CHAR_THAI 0
3691 # define MIN_CHAR_HEBREW 0
3692 # define MAX_CHAR_HEBREW 0
3693 # define MIN_CHAR_HALFWIDTH_KATAKANA 0
3694 # define MAX_CHAR_HALFWIDTH_KATAKANA 0
3695 #endif
3696   staticpro (&Vcharset_ascii);
3697   Vcharset_ascii =
3698     make_charset (LEADING_BYTE_ASCII, Qascii, 94, 1,
3699                   1, 0, 'B', CHARSET_LEFT_TO_RIGHT,
3700                   build_string ("ASCII"),
3701                   build_string ("ASCII)"),
3702                   build_string ("ASCII (ISO646 IRV)"),
3703                   build_string ("\\(iso8859-[0-9]*\\|-ascii\\)"),
3704                   Qnil, 0, 0x7F, 0, 0);
3705   staticpro (&Vcharset_control_1);
3706   Vcharset_control_1 =
3707     make_charset (LEADING_BYTE_CONTROL_1, Qcontrol_1, 94, 1,
3708                   1, 1, 0, CHARSET_LEFT_TO_RIGHT,
3709                   build_string ("C1"),
3710                   build_string ("Control characters"),
3711                   build_string ("Control characters 128-191"),
3712                   build_string (""),
3713                   Qnil, 0x80, 0x9F, 0, 0);
3714   staticpro (&Vcharset_latin_iso8859_1);
3715   Vcharset_latin_iso8859_1 =
3716     make_charset (LEADING_BYTE_LATIN_ISO8859_1, Qlatin_iso8859_1, 96, 1,
3717                   1, 1, 'A', CHARSET_LEFT_TO_RIGHT,
3718                   build_string ("Latin-1"),
3719                   build_string ("ISO8859-1 (Latin-1)"),
3720                   build_string ("ISO8859-1 (Latin-1)"),
3721                   build_string ("iso8859-1"),
3722                   Qnil, 0xA0, 0xFF, 0, 32);
3723   staticpro (&Vcharset_latin_iso8859_2);
3724   Vcharset_latin_iso8859_2 =
3725     make_charset (LEADING_BYTE_LATIN_ISO8859_2, Qlatin_iso8859_2, 96, 1,
3726                   1, 1, 'B', CHARSET_LEFT_TO_RIGHT,
3727                   build_string ("Latin-2"),
3728                   build_string ("ISO8859-2 (Latin-2)"),
3729                   build_string ("ISO8859-2 (Latin-2)"),
3730                   build_string ("iso8859-2"),
3731                   Qnil, 0, 0, 0, 32);
3732   staticpro (&Vcharset_latin_iso8859_3);
3733   Vcharset_latin_iso8859_3 =
3734     make_charset (LEADING_BYTE_LATIN_ISO8859_3, Qlatin_iso8859_3, 96, 1,
3735                   1, 1, 'C', CHARSET_LEFT_TO_RIGHT,
3736                   build_string ("Latin-3"),
3737                   build_string ("ISO8859-3 (Latin-3)"),
3738                   build_string ("ISO8859-3 (Latin-3)"),
3739                   build_string ("iso8859-3"),
3740                   Qnil, 0, 0, 0, 32);
3741   staticpro (&Vcharset_latin_iso8859_4);
3742   Vcharset_latin_iso8859_4 =
3743     make_charset (LEADING_BYTE_LATIN_ISO8859_4, Qlatin_iso8859_4, 96, 1,
3744                   1, 1, 'D', CHARSET_LEFT_TO_RIGHT,
3745                   build_string ("Latin-4"),
3746                   build_string ("ISO8859-4 (Latin-4)"),
3747                   build_string ("ISO8859-4 (Latin-4)"),
3748                   build_string ("iso8859-4"),
3749                   Qnil, 0, 0, 0, 32);
3750   staticpro (&Vcharset_thai_tis620);
3751   Vcharset_thai_tis620 =
3752     make_charset (LEADING_BYTE_THAI_TIS620, Qthai_tis620, 96, 1,
3753                   1, 1, 'T', CHARSET_LEFT_TO_RIGHT,
3754                   build_string ("TIS620"),
3755                   build_string ("TIS620 (Thai)"),
3756                   build_string ("TIS620.2529 (Thai)"),
3757                   build_string ("tis620"),
3758                   Qnil, MIN_CHAR_THAI, MAX_CHAR_THAI, 0, 32);
3759   staticpro (&Vcharset_greek_iso8859_7);
3760   Vcharset_greek_iso8859_7 =
3761     make_charset (LEADING_BYTE_GREEK_ISO8859_7, Qgreek_iso8859_7, 96, 1,
3762                   1, 1, 'F', CHARSET_LEFT_TO_RIGHT,
3763                   build_string ("ISO8859-7"),
3764                   build_string ("ISO8859-7 (Greek)"),
3765                   build_string ("ISO8859-7 (Greek)"),
3766                   build_string ("iso8859-7"),
3767                   Qnil,
3768                   0 /* MIN_CHAR_GREEK */,
3769                   0 /* MAX_CHAR_GREEK */, 0, 32);
3770   staticpro (&Vcharset_arabic_iso8859_6);
3771   Vcharset_arabic_iso8859_6 =
3772     make_charset (LEADING_BYTE_ARABIC_ISO8859_6, Qarabic_iso8859_6, 96, 1,
3773                   1, 1, 'G', CHARSET_RIGHT_TO_LEFT,
3774                   build_string ("ISO8859-6"),
3775                   build_string ("ISO8859-6 (Arabic)"),
3776                   build_string ("ISO8859-6 (Arabic)"),
3777                   build_string ("iso8859-6"),
3778                   Qnil, 0, 0, 0, 32);
3779   staticpro (&Vcharset_hebrew_iso8859_8);
3780   Vcharset_hebrew_iso8859_8 =
3781     make_charset (LEADING_BYTE_HEBREW_ISO8859_8, Qhebrew_iso8859_8, 96, 1,
3782                   1, 1, 'H', CHARSET_RIGHT_TO_LEFT,
3783                   build_string ("ISO8859-8"),
3784                   build_string ("ISO8859-8 (Hebrew)"),
3785                   build_string ("ISO8859-8 (Hebrew)"),
3786                   build_string ("iso8859-8"),
3787                   Qnil, MIN_CHAR_HEBREW, MAX_CHAR_HEBREW, 0, 32);
3788   staticpro (&Vcharset_katakana_jisx0201);
3789   Vcharset_katakana_jisx0201 =
3790     make_charset (LEADING_BYTE_KATAKANA_JISX0201, Qkatakana_jisx0201, 94, 1,
3791                   1, 1, 'I', CHARSET_LEFT_TO_RIGHT,
3792                   build_string ("JISX0201 Kana"),
3793                   build_string ("JISX0201.1976 (Japanese Kana)"),
3794                   build_string ("JISX0201.1976 Japanese Kana"),
3795                   build_string ("jisx0201\\.1976"),
3796                   Qnil, 0, 0, 0, 33);
3797   staticpro (&Vcharset_latin_jisx0201);
3798   Vcharset_latin_jisx0201 =
3799     make_charset (LEADING_BYTE_LATIN_JISX0201, Qlatin_jisx0201, 94, 1,
3800                   1, 0, 'J', CHARSET_LEFT_TO_RIGHT,
3801                   build_string ("JISX0201 Roman"),
3802                   build_string ("JISX0201.1976 (Japanese Roman)"),
3803                   build_string ("JISX0201.1976 Japanese Roman"),
3804                   build_string ("jisx0201\\.1976"),
3805                   Qnil, 0, 0, 0, 33);
3806   staticpro (&Vcharset_cyrillic_iso8859_5);
3807   Vcharset_cyrillic_iso8859_5 =
3808     make_charset (LEADING_BYTE_CYRILLIC_ISO8859_5, Qcyrillic_iso8859_5, 96, 1,
3809                   1, 1, 'L', CHARSET_LEFT_TO_RIGHT,
3810                   build_string ("ISO8859-5"),
3811                   build_string ("ISO8859-5 (Cyrillic)"),
3812                   build_string ("ISO8859-5 (Cyrillic)"),
3813                   build_string ("iso8859-5"),
3814                   Qnil,
3815                   0 /* MIN_CHAR_CYRILLIC */,
3816                   0 /* MAX_CHAR_CYRILLIC */, 0, 32);
3817   staticpro (&Vcharset_latin_iso8859_9);
3818   Vcharset_latin_iso8859_9 =
3819     make_charset (LEADING_BYTE_LATIN_ISO8859_9, Qlatin_iso8859_9, 96, 1,
3820                   1, 1, 'M', CHARSET_LEFT_TO_RIGHT,
3821                   build_string ("Latin-5"),
3822                   build_string ("ISO8859-9 (Latin-5)"),
3823                   build_string ("ISO8859-9 (Latin-5)"),
3824                   build_string ("iso8859-9"),
3825                   Qnil, 0, 0, 0, 32);
3826   staticpro (&Vcharset_japanese_jisx0208_1978);
3827   Vcharset_japanese_jisx0208_1978 =
3828     make_charset (LEADING_BYTE_JAPANESE_JISX0208_1978,
3829                   Qjapanese_jisx0208_1978, 94, 2,
3830                   2, 0, '@', CHARSET_LEFT_TO_RIGHT,
3831                   build_string ("JIS X0208:1978"),
3832                   build_string ("JIS X0208:1978 (Japanese)"),
3833                   build_string
3834                   ("JIS X0208:1978 Japanese Kanji (so called \"old JIS\")"),
3835                   build_string ("\\(jisx0208\\|jisc6226\\)\\.1978"),
3836                   Qnil, 0, 0, 0, 33);
3837   staticpro (&Vcharset_chinese_gb2312);
3838   Vcharset_chinese_gb2312 =
3839     make_charset (LEADING_BYTE_CHINESE_GB2312, Qchinese_gb2312, 94, 2,
3840                   2, 0, 'A', CHARSET_LEFT_TO_RIGHT,
3841                   build_string ("GB2312"),
3842                   build_string ("GB2312)"),
3843                   build_string ("GB2312 Chinese simplified"),
3844                   build_string ("gb2312"),
3845                   Qnil, 0, 0, 0, 33);
3846   staticpro (&Vcharset_japanese_jisx0208);
3847   Vcharset_japanese_jisx0208 =
3848     make_charset (LEADING_BYTE_JAPANESE_JISX0208, Qjapanese_jisx0208, 94, 2,
3849                   2, 0, 'B', CHARSET_LEFT_TO_RIGHT,
3850                   build_string ("JISX0208"),
3851                   build_string ("JIS X0208:1983 (Japanese)"),
3852                   build_string ("JIS X0208:1983 Japanese Kanji"),
3853                   build_string ("jisx0208\\.1983"),
3854                   Qnil, 0, 0, 0, 33);
3855 #ifdef UTF2000
3856   staticpro (&Vcharset_japanese_jisx0208_1990);
3857   Vcharset_japanese_jisx0208_1990 =
3858     make_charset (LEADING_BYTE_JAPANESE_JISX0208_1990,
3859                   Qjapanese_jisx0208_1990, 94, 2,
3860                   2, 0, 0, CHARSET_LEFT_TO_RIGHT,
3861                   build_string ("JISX0208-1990"),
3862                   build_string ("JIS X0208:1990 (Japanese)"),
3863                   build_string ("JIS X0208:1990 Japanese Kanji"),
3864                   build_string ("jisx0208\\.1990"),
3865                   Qnil,
3866                   MIN_CHAR_JIS_X0208_1990,
3867                   MAX_CHAR_JIS_X0208_1990, 0, 33);
3868 #endif
3869   staticpro (&Vcharset_korean_ksc5601);
3870   Vcharset_korean_ksc5601 =
3871     make_charset (LEADING_BYTE_KOREAN_KSC5601, Qkorean_ksc5601, 94, 2,
3872                   2, 0, 'C', CHARSET_LEFT_TO_RIGHT,
3873                   build_string ("KSC5601"),
3874                   build_string ("KSC5601 (Korean"),
3875                   build_string ("KSC5601 Korean Hangul and Hanja"),
3876                   build_string ("ksc5601"),
3877                   Qnil, 0, 0, 0, 33);
3878   staticpro (&Vcharset_japanese_jisx0212);
3879   Vcharset_japanese_jisx0212 =
3880     make_charset (LEADING_BYTE_JAPANESE_JISX0212, Qjapanese_jisx0212, 94, 2,
3881                   2, 0, 'D', CHARSET_LEFT_TO_RIGHT,
3882                   build_string ("JISX0212"),
3883                   build_string ("JISX0212 (Japanese)"),
3884                   build_string ("JISX0212 Japanese Supplement"),
3885                   build_string ("jisx0212"),
3886                   Qnil, 0, 0, 0, 33);
3887
3888 #define CHINESE_CNS_PLANE_RE(n) "cns11643[.-]\\(.*[.-]\\)?" n "$"
3889   staticpro (&Vcharset_chinese_cns11643_1);
3890   Vcharset_chinese_cns11643_1 =
3891     make_charset (LEADING_BYTE_CHINESE_CNS11643_1, Qchinese_cns11643_1, 94, 2,
3892                   2, 0, 'G', CHARSET_LEFT_TO_RIGHT,
3893                   build_string ("CNS11643-1"),
3894                   build_string ("CNS11643-1 (Chinese traditional)"),
3895                   build_string
3896                   ("CNS 11643 Plane 1 Chinese traditional"),
3897                   build_string (CHINESE_CNS_PLANE_RE("1")),
3898                   Qnil, 0, 0, 0, 33);
3899   staticpro (&Vcharset_chinese_cns11643_2);
3900   Vcharset_chinese_cns11643_2 =
3901     make_charset (LEADING_BYTE_CHINESE_CNS11643_2, Qchinese_cns11643_2, 94, 2,
3902                   2, 0, 'H', CHARSET_LEFT_TO_RIGHT,
3903                   build_string ("CNS11643-2"),
3904                   build_string ("CNS11643-2 (Chinese traditional)"),
3905                   build_string
3906                   ("CNS 11643 Plane 2 Chinese traditional"),
3907                   build_string (CHINESE_CNS_PLANE_RE("2")),
3908                   Qnil, 0, 0, 0, 33);
3909 #ifdef UTF2000
3910   staticpro (&Vcharset_latin_tcvn5712);
3911   Vcharset_latin_tcvn5712 =
3912     make_charset (LEADING_BYTE_LATIN_TCVN5712, Qlatin_tcvn5712, 96, 1,
3913                   1, 1, 'Z', CHARSET_LEFT_TO_RIGHT,
3914                   build_string ("TCVN 5712"),
3915                   build_string ("TCVN 5712 (VSCII-2)"),
3916                   build_string ("Vietnamese TCVN 5712:1983 (VSCII-2)"),
3917                   build_string ("tcvn5712-1"),
3918                   Qnil, 0, 0, 0, 32);
3919   staticpro (&Vcharset_latin_viscii_lower);
3920   Vcharset_latin_viscii_lower =
3921     make_charset (LEADING_BYTE_LATIN_VISCII_LOWER, Qlatin_viscii_lower, 96, 1,
3922                   1, 1, '1', CHARSET_LEFT_TO_RIGHT,
3923                   build_string ("VISCII lower"),
3924                   build_string ("VISCII lower (Vietnamese)"),
3925                   build_string ("VISCII lower (Vietnamese)"),
3926                   build_string ("MULEVISCII-LOWER"),
3927                   Qnil, 0, 0, 0, 32);
3928   staticpro (&Vcharset_latin_viscii_upper);
3929   Vcharset_latin_viscii_upper =
3930     make_charset (LEADING_BYTE_LATIN_VISCII_UPPER, Qlatin_viscii_upper, 96, 1,
3931                   1, 1, '2', CHARSET_LEFT_TO_RIGHT,
3932                   build_string ("VISCII upper"),
3933                   build_string ("VISCII upper (Vietnamese)"),
3934                   build_string ("VISCII upper (Vietnamese)"),
3935                   build_string ("MULEVISCII-UPPER"),
3936                   Qnil, 0, 0, 0, 32);
3937   staticpro (&Vcharset_latin_viscii);
3938   Vcharset_latin_viscii =
3939     make_charset (LEADING_BYTE_LATIN_VISCII, Qlatin_viscii, 256, 1,
3940                   1, 2, 0, CHARSET_LEFT_TO_RIGHT,
3941                   build_string ("VISCII"),
3942                   build_string ("VISCII 1.1 (Vietnamese)"),
3943                   build_string ("VISCII 1.1 (Vietnamese)"),
3944                   build_string ("VISCII1\\.1"),
3945                   Qnil, 0, 0, 0, 0);
3946   staticpro (&Vcharset_chinese_big5);
3947   Vcharset_chinese_big5 =
3948     make_charset (LEADING_BYTE_CHINESE_BIG5, Qchinese_big5, 256, 2,
3949                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
3950                   build_string ("Big5"),
3951                   build_string ("Big5"),
3952                   build_string ("Big5 Chinese traditional"),
3953                   build_string ("big5"),
3954                   Qnil, 0, 0, 0, 0);
3955   staticpro (&Vcharset_ideograph_daikanwa);
3956   Vcharset_ideograph_daikanwa =
3957     make_charset (LEADING_BYTE_DAIKANWA, Qideograph_daikanwa, 256, 2,
3958                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
3959                   build_string ("Daikanwa"),
3960                   build_string ("Morohashi's Daikanwa"),
3961                   build_string ("Daikanwa dictionary by MOROHASHI Tetsuji"),
3962                   build_string ("Daikanwa"),
3963                   Qnil, MIN_CHAR_DAIKANWA, MAX_CHAR_DAIKANWA, 0, 0);
3964   staticpro (&Vcharset_mojikyo);
3965   Vcharset_mojikyo =
3966     make_charset (LEADING_BYTE_MOJIKYO, Qmojikyo, 256, 3,
3967                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
3968                   build_string ("Mojikyo"),
3969                   build_string ("Mojikyo"),
3970                   build_string ("Konjaku-Mojikyo"),
3971                   build_string (""),
3972                   Qnil, MIN_CHAR_MOJIKYO, MAX_CHAR_MOJIKYO, 0, 0);
3973   staticpro (&Vcharset_mojikyo_2022_1);
3974   Vcharset_mojikyo_2022_1 =
3975     make_charset (LEADING_BYTE_MOJIKYO_2022_1, Qmojikyo_2022_1, 94, 3,
3976                   2, 2, ':', CHARSET_LEFT_TO_RIGHT,
3977                   build_string ("Mojikyo-2022-1"),
3978                   build_string ("Mojikyo ISO-2022 Part 1"),
3979                   build_string ("Konjaku-Mojikyo for ISO/IEC 2022 Part 1"),
3980                   build_string (""),
3981                   Qnil, 0, 0, 0, 33);
3982
3983 #define DEF_MOJIKYO_PJ(n)                                                  \
3984   staticpro (&Vcharset_mojikyo_pj_##n);                                    \
3985   Vcharset_mojikyo_pj_##n =                                                \
3986     make_charset (LEADING_BYTE_MOJIKYO_PJ_##n, Qmojikyo_pj_##n, 94, 2,     \
3987                   2, 0, 0, CHARSET_LEFT_TO_RIGHT,                          \
3988                   build_string ("Mojikyo-PJ-"#n),                          \
3989                   build_string ("Mojikyo (pseudo JIS encoding) part "#n), \
3990                   build_string                                             \
3991                   ("Konjaku-Mojikyo (pseudo JIS encoding) part "#n),       \
3992                   build_string                                             \
3993                   ("\\(MojikyoPJ-"#n "\\|jisx0208\\.Mojikyo-"#n "\\)$"),   \
3994                   Qnil, 0, 0, 0, 33);
3995
3996   DEF_MOJIKYO_PJ (1);
3997   DEF_MOJIKYO_PJ (2);
3998   DEF_MOJIKYO_PJ (3);
3999   DEF_MOJIKYO_PJ (4);
4000   DEF_MOJIKYO_PJ (5);
4001   DEF_MOJIKYO_PJ (6);
4002   DEF_MOJIKYO_PJ (7);
4003   DEF_MOJIKYO_PJ (8);
4004   DEF_MOJIKYO_PJ (9);
4005   DEF_MOJIKYO_PJ (10);
4006   DEF_MOJIKYO_PJ (11);
4007   DEF_MOJIKYO_PJ (12);
4008   DEF_MOJIKYO_PJ (13);
4009   DEF_MOJIKYO_PJ (14);
4010   DEF_MOJIKYO_PJ (15);
4011   DEF_MOJIKYO_PJ (16);
4012   DEF_MOJIKYO_PJ (17);
4013   DEF_MOJIKYO_PJ (18);
4014   DEF_MOJIKYO_PJ (19);
4015   DEF_MOJIKYO_PJ (20);
4016   DEF_MOJIKYO_PJ (21);
4017
4018   staticpro (&Vcharset_ethiopic_ucs);
4019   Vcharset_ethiopic_ucs =
4020     make_charset (LEADING_BYTE_ETHIOPIC_UCS, Qethiopic_ucs, 256, 2,
4021                   2, 2, 0, CHARSET_LEFT_TO_RIGHT,
4022                   build_string ("Ethiopic (UCS)"),
4023                   build_string ("Ethiopic (UCS)"),
4024                   build_string ("Ethiopic of UCS"),
4025                   build_string ("Ethiopic-Unicode"),
4026                   Qnil, 0x1200, 0x137F, 0x1200, 0);
4027 #endif
4028   staticpro (&Vcharset_chinese_big5_1);
4029   Vcharset_chinese_big5_1 =
4030     make_charset (LEADING_BYTE_CHINESE_BIG5_1, Qchinese_big5_1, 94, 2,
4031                   2, 0, '0', CHARSET_LEFT_TO_RIGHT,
4032                   build_string ("Big5"),
4033                   build_string ("Big5 (Level-1)"),
4034                   build_string
4035                   ("Big5 Level-1 Chinese traditional"),
4036                   build_string ("big5"),
4037                   Qnil, 0, 0, 0, 33);
4038   staticpro (&Vcharset_chinese_big5_2);
4039   Vcharset_chinese_big5_2 =
4040     make_charset (LEADING_BYTE_CHINESE_BIG5_2, Qchinese_big5_2, 94, 2,
4041                   2, 0, '1', CHARSET_LEFT_TO_RIGHT,
4042                   build_string ("Big5"),
4043                   build_string ("Big5 (Level-2)"),
4044                   build_string
4045                   ("Big5 Level-2 Chinese traditional"),
4046                   build_string ("big5"),
4047                   Qnil, 0, 0, 0, 33);
4048
4049 #ifdef ENABLE_COMPOSITE_CHARS
4050   /* #### For simplicity, we put composite chars into a 96x96 charset.
4051      This is going to lead to problems because you can run out of
4052      room, esp. as we don't yet recycle numbers. */
4053   staticpro (&Vcharset_composite);
4054   Vcharset_composite =
4055     make_charset (LEADING_BYTE_COMPOSITE, Qcomposite, 96, 2,
4056                   2, 0, 0, CHARSET_LEFT_TO_RIGHT,
4057                   build_string ("Composite"),
4058                   build_string ("Composite characters"),
4059                   build_string ("Composite characters"),
4060                   build_string (""));
4061
4062   /* #### not dumped properly */
4063   composite_char_row_next = 32;
4064   composite_char_col_next = 32;
4065
4066   Vcomposite_char_string2char_hash_table =
4067     make_lisp_hash_table (500, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
4068   Vcomposite_char_char2string_hash_table =
4069     make_lisp_hash_table (500, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
4070   staticpro (&Vcomposite_char_string2char_hash_table);
4071   staticpro (&Vcomposite_char_char2string_hash_table);
4072 #endif /* ENABLE_COMPOSITE_CHARS */
4073
4074 }