(put_char_ccs_code_point): Store characters of =ucs whose code_points
[chise/xemacs-chise.git.1] / src / chartab.c
1 /* XEmacs routines to deal with char tables.
2    Copyright (C) 1992, 1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1995, 1997, 1999 Electrotechnical Laboratory, JAPAN.
6    Licensed to the Free Software Foundation.
7    Copyright (C) 1999,2000,2001,2002,2003,2004 MORIOKA Tomohiko
8
9 This file is part of XEmacs.
10
11 XEmacs is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2, or (at your option) any
14 later version.
15
16 XEmacs is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with XEmacs; see the file COPYING.  If not, write to
23 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 Boston, MA 02111-1307, USA.  */
25
26 /* Synched up with: Mule 2.3.  Not synched with FSF.
27
28    This file was written independently of the FSF implementation,
29    and is not compatible. */
30
31 /* Authorship:
32
33    Ben Wing: wrote, for 19.13 (Mule).  Some category table stuff
34              loosely based on the original Mule.
35    Jareth Hein: fixed a couple of bugs in the implementation, and
36              added regex support for categories with check_category_at
37    MORIOKA Tomohiko: Rewritten for XEmacs CHISE
38  */
39
40 #include <config.h>
41 #include "lisp.h"
42
43 #include "buffer.h"
44 #include "chartab.h"
45 #include "syntax.h"
46 #ifdef UTF2000
47 #include "elhash.h"
48 #endif /* UTF2000 */
49
50 Lisp_Object Qchar_tablep, Qchar_table;
51
52 Lisp_Object Vall_syntax_tables;
53
54 #ifdef MULE
55 Lisp_Object Qcategory_table_p;
56 Lisp_Object Qcategory_designator_p;
57 Lisp_Object Qcategory_table_value_p;
58
59 Lisp_Object Vstandard_category_table;
60
61 /* Variables to determine word boundary.  */
62 Lisp_Object Vword_combining_categories, Vword_separating_categories;
63 #endif /* MULE */
64
65 \f
66 #ifdef HAVE_LIBCHISE
67 Lisp_Object Vchise_db_directory;
68 Lisp_Object Vchise_system_db_directory;
69
70 CHISE_DS *default_chise_data_source = NULL;
71 #endif
72
73 #ifdef UTF2000
74
75 EXFUN (Fchar_refs_simplify_char_specs, 1);
76 extern Lisp_Object Qideographic_structure;
77
78 Lisp_Object Vnext_defined_char_id;
79 EXFUN (Fdefine_char, 1);
80
81 EXFUN (Fmap_char_attribute, 3);
82
83 #ifdef HAVE_LIBCHISE
84 EXFUN (Fmount_char_attribute_table, 1);
85 #endif
86
87 #ifdef HAVE_CHISE
88 EXFUN (Fload_char_attribute_table, 1);
89
90 Lisp_Object Vchar_db_stingy_mode;
91 #endif
92
93 #define BT_UINT8_MIN            0
94 #define BT_UINT8_MAX            (UCHAR_MAX - 4)
95 #define BT_UINT8_t              (UCHAR_MAX - 3)
96 #define BT_UINT8_nil            (UCHAR_MAX - 2)
97 #define BT_UINT8_unbound        (UCHAR_MAX - 1)
98 #define BT_UINT8_unloaded       UCHAR_MAX
99
100 INLINE_HEADER int INT_UINT8_P (Lisp_Object obj);
101 INLINE_HEADER int UINT8_VALUE_P (Lisp_Object obj);
102 INLINE_HEADER unsigned char UINT8_ENCODE (Lisp_Object obj);
103 INLINE_HEADER Lisp_Object UINT8_DECODE (unsigned char n);
104 INLINE_HEADER unsigned short UINT8_TO_UINT16 (unsigned char n);
105
106 INLINE_HEADER int
107 INT_UINT8_P (Lisp_Object obj)
108 {
109   if (INTP (obj))
110     {
111       int num = XINT (obj);
112
113       return (BT_UINT8_MIN <= num) && (num <= BT_UINT8_MAX);
114     }
115   else
116     return 0;
117 }
118
119 INLINE_HEADER int
120 UINT8_VALUE_P (Lisp_Object obj)
121 {
122   return EQ (obj, Qunloaded) || EQ (obj, Qunbound)
123     || EQ (obj, Qnil) || EQ (obj, Qt) || INT_UINT8_P (obj);
124 }
125
126 INLINE_HEADER unsigned char
127 UINT8_ENCODE (Lisp_Object obj)
128 {
129   if (EQ (obj, Qunloaded))
130     return BT_UINT8_unloaded;
131   else if (EQ (obj, Qunbound))
132     return BT_UINT8_unbound;
133   else if (EQ (obj, Qnil))
134     return BT_UINT8_nil;
135   else if (EQ (obj, Qt))
136     return BT_UINT8_t;
137   else
138     return XINT (obj);
139 }
140
141 INLINE_HEADER Lisp_Object
142 UINT8_DECODE (unsigned char n)
143 {
144   if (n == BT_UINT8_unloaded)
145     return Qunloaded;
146   else if (n == BT_UINT8_unbound)
147     return Qunbound;
148   else if (n == BT_UINT8_nil)
149     return Qnil;
150   else if (n == BT_UINT8_t)
151     return Qt;
152   else
153     return make_int (n);
154 }
155
156 static Lisp_Object
157 mark_uint8_byte_table (Lisp_Object obj)
158 {
159   return Qnil;
160 }
161
162 static void
163 print_uint8_byte_table (Lisp_Object obj,
164                         Lisp_Object printcharfun, int escapeflag)
165 {
166   Lisp_Uint8_Byte_Table *bte = XUINT8_BYTE_TABLE (obj);
167   int i;
168   struct gcpro gcpro1, gcpro2;
169   GCPRO2 (obj, printcharfun);
170
171   write_c_string ("\n#<uint8-byte-table", printcharfun);
172   for (i = 0; i < 256; i++)
173     {
174       unsigned char n = bte->property[i];
175       if ( (i & 15) == 0 )
176         write_c_string ("\n  ", printcharfun);
177       write_c_string (" ", printcharfun);
178       if (n == BT_UINT8_unbound)
179         write_c_string ("void", printcharfun);
180       else if (n == BT_UINT8_nil)
181         write_c_string ("nil", printcharfun);
182       else if (n == BT_UINT8_t)
183         write_c_string ("t", printcharfun);
184       else
185         {
186           char buf[4];
187
188           sprintf (buf, "%hd", n);
189           write_c_string (buf, printcharfun);
190         }
191     }
192   UNGCPRO;
193   write_c_string (">", printcharfun);
194 }
195
196 static int
197 uint8_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
198 {
199   Lisp_Uint8_Byte_Table *te1 = XUINT8_BYTE_TABLE (obj1);
200   Lisp_Uint8_Byte_Table *te2 = XUINT8_BYTE_TABLE (obj2);
201   int i;
202
203   for (i = 0; i < 256; i++)
204     if (te1->property[i] != te2->property[i])
205       return 0;
206   return 1;
207 }
208
209 static unsigned long
210 uint8_byte_table_hash (Lisp_Object obj, int depth)
211 {
212   Lisp_Uint8_Byte_Table *te = XUINT8_BYTE_TABLE (obj);
213   int i;
214   hashcode_t hash = 0;
215
216   for (i = 0; i < 256; i++)
217     hash = HASH2 (hash, te->property[i]);
218   return hash;
219 }
220
221 static const struct lrecord_description uint8_byte_table_description[] = {
222   { XD_END }
223 };
224
225 DEFINE_LRECORD_IMPLEMENTATION ("uint8-byte-table", uint8_byte_table,
226                                mark_uint8_byte_table,
227                                print_uint8_byte_table,
228                                0, uint8_byte_table_equal,
229                                uint8_byte_table_hash,
230                                uint8_byte_table_description,
231                                Lisp_Uint8_Byte_Table);
232
233 static Lisp_Object
234 make_uint8_byte_table (unsigned char initval)
235 {
236   Lisp_Object obj;
237   int i;
238   Lisp_Uint8_Byte_Table *cte;
239
240   cte = alloc_lcrecord_type (Lisp_Uint8_Byte_Table,
241                              &lrecord_uint8_byte_table);
242
243   for (i = 0; i < 256; i++)
244     cte->property[i] = initval;
245
246   XSETUINT8_BYTE_TABLE (obj, cte);
247   return obj;
248 }
249
250 static Lisp_Object
251 copy_uint8_byte_table (Lisp_Object entry)
252 {
253   Lisp_Uint8_Byte_Table *cte = XUINT8_BYTE_TABLE (entry);
254   Lisp_Object obj;
255   int i;
256   Lisp_Uint8_Byte_Table *ctenew
257     = alloc_lcrecord_type (Lisp_Uint8_Byte_Table,
258                            &lrecord_uint8_byte_table);
259
260   for (i = 0; i < 256; i++)
261     {
262       ctenew->property[i] = cte->property[i];
263     }
264
265   XSETUINT8_BYTE_TABLE (obj, ctenew);
266   return obj;
267 }
268
269 static int
270 uint8_byte_table_same_value_p (Lisp_Object obj)
271 {
272   Lisp_Uint8_Byte_Table *bte = XUINT8_BYTE_TABLE (obj);
273   unsigned char v0 = bte->property[0];
274   int i;
275
276   for (i = 1; i < 256; i++)
277     {
278       if (bte->property[i] != v0)
279         return 0;
280     }
281   return -1;
282 }
283
284 static int
285 map_over_uint8_byte_table (Lisp_Uint8_Byte_Table *ct, Lisp_Char_Table* root,
286                            Emchar ofs, int place,
287                            int (*fn) (struct chartab_range *range,
288                                       Lisp_Object val, void *arg),
289                            void *arg)
290 {
291   struct chartab_range rainj;
292   int i, retval;
293   int unit = 1 << (8 * place);
294   Emchar c = ofs;
295   Emchar c1;
296
297   rainj.type = CHARTAB_RANGE_CHAR;
298
299   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
300     {
301       if (ct->property[i] == BT_UINT8_unloaded)
302         {
303 #if 0
304           c1 = c + unit;
305           for (; c < c1 && retval == 0; c++)
306             {
307               Lisp_Object ret = get_char_id_table (root, c);
308
309               if (!UNBOUNDP (ret))
310                 {
311                   rainj.ch = c;
312                   retval = (fn) (&rainj, ret, arg);
313                 }
314             }
315 #else
316           ct->property[i] = BT_UINT8_unbound;
317           c += unit;
318 #endif
319         }
320       else if (ct->property[i] != BT_UINT8_unbound)
321         {
322           c1 = c + unit;
323           for (; c < c1 && retval == 0; c++)
324             {
325               rainj.ch = c;
326               retval = (fn) (&rainj, UINT8_DECODE (ct->property[i]), arg);
327             }
328         }
329       else
330         c += unit;
331     }
332   return retval;
333 }
334
335 #ifdef HAVE_CHISE
336 static void
337 save_uint8_byte_table (Lisp_Uint8_Byte_Table *ct, Lisp_Char_Table* root,
338 #ifdef HAVE_LIBCHISE
339                        CHISE_Feature feature,
340 #else
341                        Lisp_Object db,
342 #endif
343                        Emchar ofs, int place,
344                        Lisp_Object (*filter)(Lisp_Object value))
345 {
346   struct chartab_range rainj;
347   int i, retval;
348   int unit = 1 << (8 * place);
349   Emchar c = ofs;
350   Emchar c1;
351
352   rainj.type = CHARTAB_RANGE_CHAR;
353
354   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
355     {
356       if (ct->property[i] == BT_UINT8_unloaded)
357         {
358           c1 = c + unit;
359         }
360       else if (ct->property[i] != BT_UINT8_unbound)
361         {
362           c1 = c + unit;
363           for (; c < c1 && retval == 0; c++)
364             {
365 #ifdef HAVE_LIBCHISE
366               chise_char_set_feature_value
367                 (c, feature,
368                  XSTRING_DATA
369                  (Fprin1_to_string (UINT8_DECODE (ct->property[i]),
370                                     Qnil)));
371 #else
372               Fput_database (Fprin1_to_string (make_char (c), Qnil),
373                              Fprin1_to_string (UINT8_DECODE (ct->property[i]),
374                                                Qnil),
375                              db, Qt);
376 #endif
377             }
378         }
379       else
380         c += unit;
381     }
382 }
383 #endif
384
385 #define BT_UINT16_MIN           0
386 #define BT_UINT16_MAX           (USHRT_MAX - 4)
387 #define BT_UINT16_t             (USHRT_MAX - 3)
388 #define BT_UINT16_nil           (USHRT_MAX - 2)
389 #define BT_UINT16_unbound       (USHRT_MAX - 1)
390 #define BT_UINT16_unloaded      USHRT_MAX
391
392 INLINE_HEADER int INT_UINT16_P (Lisp_Object obj);
393 INLINE_HEADER int UINT16_VALUE_P (Lisp_Object obj);
394 INLINE_HEADER unsigned short UINT16_ENCODE (Lisp_Object obj);
395 INLINE_HEADER Lisp_Object UINT16_DECODE (unsigned short us);
396
397 INLINE_HEADER int
398 INT_UINT16_P (Lisp_Object obj)
399 {
400   if (INTP (obj))
401     {
402       int num = XINT (obj);
403
404       return (BT_UINT16_MIN <= num) && (num <= BT_UINT16_MAX);
405     }
406   else
407     return 0;
408 }
409
410 INLINE_HEADER int
411 UINT16_VALUE_P (Lisp_Object obj)
412 {
413   return EQ (obj, Qunloaded) || EQ (obj, Qunbound)
414     || EQ (obj, Qnil) || EQ (obj, Qt) || INT_UINT16_P (obj);
415 }
416
417 INLINE_HEADER unsigned short
418 UINT16_ENCODE (Lisp_Object obj)
419 {
420   if (EQ (obj, Qunloaded))
421     return BT_UINT16_unloaded;
422   else if (EQ (obj, Qunbound))
423     return BT_UINT16_unbound;
424   else if (EQ (obj, Qnil))
425     return BT_UINT16_nil;
426   else if (EQ (obj, Qt))
427     return BT_UINT16_t;
428   else
429     return XINT (obj);
430 }
431
432 INLINE_HEADER Lisp_Object
433 UINT16_DECODE (unsigned short n)
434 {
435   if (n == BT_UINT16_unloaded)
436     return Qunloaded;
437   else if (n == BT_UINT16_unbound)
438     return Qunbound;
439   else if (n == BT_UINT16_nil)
440     return Qnil;
441   else if (n == BT_UINT16_t)
442     return Qt;
443   else
444     return make_int (n);
445 }
446
447 INLINE_HEADER unsigned short
448 UINT8_TO_UINT16 (unsigned char n)
449 {
450   if (n == BT_UINT8_unloaded)
451     return BT_UINT16_unloaded;
452   else if (n == BT_UINT8_unbound)
453     return BT_UINT16_unbound;
454   else if (n == BT_UINT8_nil)
455     return BT_UINT16_nil;
456   else if (n == BT_UINT8_t)
457     return BT_UINT16_t;
458   else
459     return n;
460 }
461
462 static Lisp_Object
463 mark_uint16_byte_table (Lisp_Object obj)
464 {
465   return Qnil;
466 }
467
468 static void
469 print_uint16_byte_table (Lisp_Object obj,
470                          Lisp_Object printcharfun, int escapeflag)
471 {
472   Lisp_Uint16_Byte_Table *bte = XUINT16_BYTE_TABLE (obj);
473   int i;
474   struct gcpro gcpro1, gcpro2;
475   GCPRO2 (obj, printcharfun);
476
477   write_c_string ("\n#<uint16-byte-table", printcharfun);
478   for (i = 0; i < 256; i++)
479     {
480       unsigned short n = bte->property[i];
481       if ( (i & 15) == 0 )
482         write_c_string ("\n  ", printcharfun);
483       write_c_string (" ", printcharfun);
484       if (n == BT_UINT16_unbound)
485         write_c_string ("void", printcharfun);
486       else if (n == BT_UINT16_nil)
487         write_c_string ("nil", printcharfun);
488       else if (n == BT_UINT16_t)
489         write_c_string ("t", printcharfun);
490       else
491         {
492           char buf[7];
493
494           sprintf (buf, "%hd", n);
495           write_c_string (buf, printcharfun);
496         }
497     }
498   UNGCPRO;
499   write_c_string (">", printcharfun);
500 }
501
502 static int
503 uint16_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
504 {
505   Lisp_Uint16_Byte_Table *te1 = XUINT16_BYTE_TABLE (obj1);
506   Lisp_Uint16_Byte_Table *te2 = XUINT16_BYTE_TABLE (obj2);
507   int i;
508
509   for (i = 0; i < 256; i++)
510     if (te1->property[i] != te2->property[i])
511       return 0;
512   return 1;
513 }
514
515 static unsigned long
516 uint16_byte_table_hash (Lisp_Object obj, int depth)
517 {
518   Lisp_Uint16_Byte_Table *te = XUINT16_BYTE_TABLE (obj);
519   int i;
520   hashcode_t hash = 0;
521
522   for (i = 0; i < 256; i++)
523     hash = HASH2 (hash, te->property[i]);
524   return hash;
525 }
526
527 static const struct lrecord_description uint16_byte_table_description[] = {
528   { XD_END }
529 };
530
531 DEFINE_LRECORD_IMPLEMENTATION ("uint16-byte-table", uint16_byte_table,
532                                mark_uint16_byte_table,
533                                print_uint16_byte_table,
534                                0, uint16_byte_table_equal,
535                                uint16_byte_table_hash,
536                                uint16_byte_table_description,
537                                Lisp_Uint16_Byte_Table);
538
539 static Lisp_Object
540 make_uint16_byte_table (unsigned short initval)
541 {
542   Lisp_Object obj;
543   int i;
544   Lisp_Uint16_Byte_Table *cte;
545
546   cte = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
547                              &lrecord_uint16_byte_table);
548
549   for (i = 0; i < 256; i++)
550     cte->property[i] = initval;
551
552   XSETUINT16_BYTE_TABLE (obj, cte);
553   return obj;
554 }
555
556 static Lisp_Object
557 copy_uint16_byte_table (Lisp_Object entry)
558 {
559   Lisp_Uint16_Byte_Table *cte = XUINT16_BYTE_TABLE (entry);
560   Lisp_Object obj;
561   int i;
562   Lisp_Uint16_Byte_Table *ctenew
563     = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
564                            &lrecord_uint16_byte_table);
565
566   for (i = 0; i < 256; i++)
567     {
568       ctenew->property[i] = cte->property[i];
569     }
570
571   XSETUINT16_BYTE_TABLE (obj, ctenew);
572   return obj;
573 }
574
575 static Lisp_Object
576 expand_uint8_byte_table_to_uint16 (Lisp_Object table)
577 {
578   Lisp_Object obj;
579   int i;
580   Lisp_Uint8_Byte_Table* bte = XUINT8_BYTE_TABLE(table);
581   Lisp_Uint16_Byte_Table* cte;
582
583   cte = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
584                              &lrecord_uint16_byte_table);
585   for (i = 0; i < 256; i++)
586     {
587       cte->property[i] = UINT8_TO_UINT16 (bte->property[i]);
588     }
589   XSETUINT16_BYTE_TABLE (obj, cte);
590   return obj;
591 }
592
593 static int
594 uint16_byte_table_same_value_p (Lisp_Object obj)
595 {
596   Lisp_Uint16_Byte_Table *bte = XUINT16_BYTE_TABLE (obj);
597   unsigned short v0 = bte->property[0];
598   int i;
599
600   for (i = 1; i < 256; i++)
601     {
602       if (bte->property[i] != v0)
603         return 0;
604     }
605   return -1;
606 }
607
608 static int
609 map_over_uint16_byte_table (Lisp_Uint16_Byte_Table *ct, Lisp_Char_Table* root,
610                             Emchar ofs, int place,
611                             int (*fn) (struct chartab_range *range,
612                                        Lisp_Object val, void *arg),
613                             void *arg)
614 {
615   struct chartab_range rainj;
616   int i, retval;
617   int unit = 1 << (8 * place);
618   Emchar c = ofs;
619   Emchar c1;
620
621   rainj.type = CHARTAB_RANGE_CHAR;
622
623   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
624     {
625       if (ct->property[i] == BT_UINT16_unloaded)
626         {
627 #if 0
628           c1 = c + unit;
629           for (; c < c1 && retval == 0; c++)
630             {
631               Lisp_Object ret = get_char_id_table (root, c);
632
633               if (!UNBOUNDP (ret))
634                 {
635                   rainj.ch = c;
636                   retval = (fn) (&rainj, ret, arg);
637                 }
638             }
639 #else
640           ct->property[i] = BT_UINT16_unbound;
641           c += unit;
642 #endif
643         }
644       else if (ct->property[i] != BT_UINT16_unbound)
645         {
646           c1 = c + unit;
647           for (; c < c1 && retval == 0; c++)
648             {
649               rainj.ch = c;
650               retval = (fn) (&rainj, UINT16_DECODE (ct->property[i]), arg);
651             }
652         }
653       else
654         c += unit;
655     }
656   return retval;
657 }
658
659 #ifdef HAVE_CHISE
660 static void
661 save_uint16_byte_table (Lisp_Uint16_Byte_Table *ct, Lisp_Char_Table* root,
662 #ifdef HAVE_LIBCHISE
663                         CHISE_Feature feature,
664 #else
665                         Lisp_Object db,
666 #endif
667                         Emchar ofs, int place,
668                         Lisp_Object (*filter)(Lisp_Object value))
669 {
670   struct chartab_range rainj;
671   int i, retval;
672   int unit = 1 << (8 * place);
673   Emchar c = ofs;
674   Emchar c1;
675
676   rainj.type = CHARTAB_RANGE_CHAR;
677
678   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
679     {
680       if (ct->property[i] == BT_UINT16_unloaded)
681         {
682           c1 = c + unit;
683         }
684       else if (ct->property[i] != BT_UINT16_unbound)
685         {
686           c1 = c + unit;
687           for (; c < c1 && retval == 0; c++)
688             {
689 #ifdef HAVE_LIBCHISE
690               chise_char_set_feature_value
691                 (c, feature,
692                  XSTRING_DATA
693                  (Fprin1_to_string (UINT16_DECODE (ct->property[i]),
694                                     Qnil)));
695 #else
696               Fput_database (Fprin1_to_string (make_char (c), Qnil),
697                              Fprin1_to_string (UINT16_DECODE (ct->property[i]),
698                                                Qnil),
699                              db, Qt);
700 #endif
701             }
702         }
703       else
704         c += unit;
705     }
706 }
707 #endif
708
709
710 static Lisp_Object
711 mark_byte_table (Lisp_Object obj)
712 {
713   Lisp_Byte_Table *cte = XBYTE_TABLE (obj);
714   int i;
715
716   for (i = 0; i < 256; i++)
717     {
718       mark_object (cte->property[i]);
719     }
720   return Qnil;
721 }
722
723 static void
724 print_byte_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
725 {
726   Lisp_Byte_Table *bte = XBYTE_TABLE (obj);
727   int i;
728   struct gcpro gcpro1, gcpro2;
729   GCPRO2 (obj, printcharfun);
730
731   write_c_string ("\n#<byte-table", printcharfun);
732   for (i = 0; i < 256; i++)
733     {
734       Lisp_Object elt = bte->property[i];
735       if ( (i & 15) == 0 )
736         write_c_string ("\n  ", printcharfun);
737       write_c_string (" ", printcharfun);
738       if (EQ (elt, Qunbound))
739         write_c_string ("void", printcharfun);
740       else
741         print_internal (elt, printcharfun, escapeflag);
742     }
743   UNGCPRO;
744   write_c_string (">", printcharfun);
745 }
746
747 static int
748 byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
749 {
750   Lisp_Byte_Table *cte1 = XBYTE_TABLE (obj1);
751   Lisp_Byte_Table *cte2 = XBYTE_TABLE (obj2);
752   int i;
753
754   for (i = 0; i < 256; i++)
755     if (BYTE_TABLE_P (cte1->property[i]))
756       {
757         if (BYTE_TABLE_P (cte2->property[i]))
758           {
759             if (!byte_table_equal (cte1->property[i],
760                                    cte2->property[i], depth + 1))
761               return 0;
762           }
763         else
764           return 0;
765       }
766     else
767       if (!internal_equal (cte1->property[i], cte2->property[i], depth + 1))
768         return 0;
769   return 1;
770 }
771
772 static unsigned long
773 byte_table_hash (Lisp_Object obj, int depth)
774 {
775   Lisp_Byte_Table *cte = XBYTE_TABLE (obj);
776
777   return internal_array_hash (cte->property, 256, depth);
778 }
779
780 static const struct lrecord_description byte_table_description[] = {
781   { XD_LISP_OBJECT_ARRAY, offsetof(Lisp_Byte_Table, property), 256 },
782   { XD_END }
783 };
784
785 DEFINE_LRECORD_IMPLEMENTATION ("byte-table", byte_table,
786                                mark_byte_table,
787                                print_byte_table,
788                                0, byte_table_equal,
789                                byte_table_hash,
790                                byte_table_description,
791                                Lisp_Byte_Table);
792
793 static Lisp_Object
794 make_byte_table (Lisp_Object initval)
795 {
796   Lisp_Object obj;
797   int i;
798   Lisp_Byte_Table *cte;
799
800   cte = alloc_lcrecord_type (Lisp_Byte_Table, &lrecord_byte_table);
801
802   for (i = 0; i < 256; i++)
803     cte->property[i] = initval;
804
805   XSETBYTE_TABLE (obj, cte);
806   return obj;
807 }
808
809 static Lisp_Object
810 copy_byte_table (Lisp_Object entry)
811 {
812   Lisp_Byte_Table *cte = XBYTE_TABLE (entry);
813   Lisp_Object obj;
814   int i;
815   Lisp_Byte_Table *ctnew
816     = alloc_lcrecord_type (Lisp_Byte_Table, &lrecord_byte_table);
817
818   for (i = 0; i < 256; i++)
819     {
820       if (UINT8_BYTE_TABLE_P (cte->property[i]))
821         {
822           ctnew->property[i] = copy_uint8_byte_table (cte->property[i]);
823         }
824       else if (UINT16_BYTE_TABLE_P (cte->property[i]))
825         {
826           ctnew->property[i] = copy_uint16_byte_table (cte->property[i]);
827         }
828       else if (BYTE_TABLE_P (cte->property[i]))
829         {
830           ctnew->property[i] = copy_byte_table (cte->property[i]);
831         }
832       else
833         ctnew->property[i] = cte->property[i];
834     }
835
836   XSETBYTE_TABLE (obj, ctnew);
837   return obj;
838 }
839
840 static int
841 byte_table_same_value_p (Lisp_Object obj)
842 {
843   Lisp_Byte_Table *bte = XBYTE_TABLE (obj);
844   Lisp_Object v0 = bte->property[0];
845   int i;
846
847   for (i = 1; i < 256; i++)
848     {
849       if (!internal_equal (bte->property[i], v0, 0))
850         return 0;
851     }
852   return -1;
853 }
854
855 static int
856 map_over_byte_table (Lisp_Byte_Table *ct, Lisp_Char_Table* root,
857                      Emchar ofs, int place,
858                      int (*fn) (struct chartab_range *range,
859                                 Lisp_Object val, void *arg),
860                      void *arg)
861 {
862   int i, retval;
863   Lisp_Object v;
864   int unit = 1 << (8 * place);
865   Emchar c = ofs;
866
867   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
868     {
869       v = ct->property[i];
870       if (UINT8_BYTE_TABLE_P (v))
871         {
872           retval
873             = map_over_uint8_byte_table (XUINT8_BYTE_TABLE(v), root,
874                                          c, place - 1, fn, arg);
875           c += unit;
876         }
877       else if (UINT16_BYTE_TABLE_P (v))
878         {
879           retval
880             = map_over_uint16_byte_table (XUINT16_BYTE_TABLE(v), root,
881                                           c, place - 1, fn, arg);
882           c += unit;
883         }
884       else if (BYTE_TABLE_P (v))
885         {
886           retval = map_over_byte_table (XBYTE_TABLE(v), root,
887                                         c, place - 1, fn, arg);
888           c += unit;
889         }
890       else if (EQ (v, Qunloaded))
891         {
892 #if 0
893           struct chartab_range rainj;
894           Emchar c1 = c + unit;
895
896           rainj.type = CHARTAB_RANGE_CHAR;
897
898           for (; c < c1 && retval == 0; c++)
899             {
900               Lisp_Object ret = get_char_id_table (root, c);
901
902               if (!UNBOUNDP (ret))
903                 {
904                   rainj.ch = c;
905                   retval = (fn) (&rainj, ret, arg);
906                 }
907             }
908 #else
909           ct->property[i] = Qunbound;
910           c += unit;
911 #endif
912         }
913       else if (!UNBOUNDP (v))
914         {
915           struct chartab_range rainj;
916           Emchar c1 = c + unit;
917
918           rainj.type = CHARTAB_RANGE_CHAR;
919
920           for (; c < c1 && retval == 0; c++)
921             {
922               rainj.ch = c;
923               retval = (fn) (&rainj, v, arg);
924             }
925         }
926       else
927         c += unit;
928     }
929   return retval;
930 }
931
932 #ifdef HAVE_CHISE
933 static void
934 save_byte_table (Lisp_Byte_Table *ct, Lisp_Char_Table* root,
935 #ifdef HAVE_LIBCHISE
936                  CHISE_Feature feature,
937 #else
938                  Lisp_Object db,
939 #endif
940                  Emchar ofs, int place,
941                  Lisp_Object (*filter)(Lisp_Object value))
942 {
943   int i, retval;
944   Lisp_Object v;
945   int unit = 1 << (8 * place);
946   Emchar c = ofs;
947
948   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
949     {
950       v = ct->property[i];
951       if (UINT8_BYTE_TABLE_P (v))
952         {
953           save_uint8_byte_table (XUINT8_BYTE_TABLE(v), root,
954 #ifdef HAVE_LIBCHISE
955                                  feature,
956 #else
957                                  db,
958 #endif
959                                  c, place - 1, filter);
960           c += unit;
961         }
962       else if (UINT16_BYTE_TABLE_P (v))
963         {
964           save_uint16_byte_table (XUINT16_BYTE_TABLE(v), root,
965 #ifdef HAVE_LIBCHISE
966                                   feature,
967 #else
968                                   db,
969 #endif
970                                   c, place - 1, filter);
971           c += unit;
972         }
973       else if (BYTE_TABLE_P (v))
974         {
975           save_byte_table (XBYTE_TABLE(v), root,
976 #ifdef HAVE_LIBCHISE
977                            feature,
978 #else
979                            db,
980 #endif
981                            c, place - 1, filter);
982           c += unit;
983         }
984       else if (EQ (v, Qunloaded))
985         {
986           c += unit;
987         }
988       else if (!UNBOUNDP (v))
989         {
990           struct chartab_range rainj;
991           Emchar c1 = c + unit;
992
993           if (filter != NULL)
994             v = (*filter)(v);
995
996           rainj.type = CHARTAB_RANGE_CHAR;
997
998           for (; c < c1 && retval == 0; c++)
999             {
1000 #ifdef HAVE_LIBCHISE
1001               chise_char_set_feature_value
1002                 (c, feature, XSTRING_DATA (Fprin1_to_string (v, Qnil)));
1003 #else
1004               Fput_database (Fprin1_to_string (make_char (c), Qnil),
1005                              Fprin1_to_string (v, Qnil),
1006                              db, Qt);
1007 #endif
1008             }
1009         }
1010       else
1011         c += unit;
1012     }
1013 }
1014 #endif
1015
1016 Lisp_Object
1017 get_byte_table (Lisp_Object table, unsigned char idx)
1018 {
1019   if (UINT8_BYTE_TABLE_P (table))
1020     return UINT8_DECODE (XUINT8_BYTE_TABLE(table)->property[idx]);
1021   else if (UINT16_BYTE_TABLE_P (table))
1022     return UINT16_DECODE (XUINT16_BYTE_TABLE(table)->property[idx]);
1023   else if (BYTE_TABLE_P (table))
1024     return XBYTE_TABLE(table)->property[idx];
1025   else
1026     return table;
1027 }
1028
1029 Lisp_Object
1030 put_byte_table (Lisp_Object table, unsigned char idx, Lisp_Object value)
1031 {
1032   if (UINT8_BYTE_TABLE_P (table))
1033     {
1034       if (UINT8_VALUE_P (value))
1035         {
1036           XUINT8_BYTE_TABLE(table)->property[idx] = UINT8_ENCODE (value);
1037           if (!UINT8_BYTE_TABLE_P (value) &&
1038               !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
1039               && uint8_byte_table_same_value_p (table))
1040             {
1041               return value;
1042             }
1043         }
1044       else if (UINT16_VALUE_P (value))
1045         {
1046           Lisp_Object new = expand_uint8_byte_table_to_uint16 (table);
1047
1048           XUINT16_BYTE_TABLE(new)->property[idx] = UINT16_ENCODE (value);
1049           return new;
1050         }
1051       else
1052         {
1053           Lisp_Object new = make_byte_table (Qnil);
1054           int i;
1055
1056           for (i = 0; i < 256; i++)
1057             {
1058               XBYTE_TABLE(new)->property[i]
1059                 = UINT8_DECODE (XUINT8_BYTE_TABLE(table)->property[i]);
1060             }
1061           XBYTE_TABLE(new)->property[idx] = value;
1062           return new;
1063         }
1064     }
1065   else if (UINT16_BYTE_TABLE_P (table))
1066     {
1067       if (UINT16_VALUE_P (value))
1068         {
1069           XUINT16_BYTE_TABLE(table)->property[idx] = UINT16_ENCODE (value);
1070           if (!UINT8_BYTE_TABLE_P (value) &&
1071               !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
1072               && uint16_byte_table_same_value_p (table))
1073             {
1074               return value;
1075             }
1076         }
1077       else
1078         {
1079           Lisp_Object new = make_byte_table (Qnil);
1080           int i;
1081
1082           for (i = 0; i < 256; i++)
1083             {
1084               XBYTE_TABLE(new)->property[i]
1085                 = UINT16_DECODE (XUINT16_BYTE_TABLE(table)->property[i]);
1086             }
1087           XBYTE_TABLE(new)->property[idx] = value;
1088           return new;
1089         }
1090     }
1091   else if (BYTE_TABLE_P (table))
1092     {
1093       XBYTE_TABLE(table)->property[idx] = value;
1094       if (!UINT8_BYTE_TABLE_P (value) &&
1095           !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
1096           && byte_table_same_value_p (table))
1097         {
1098           return value;
1099         }
1100     }
1101   else if (!internal_equal (table, value, 0))
1102     {
1103       if (UINT8_VALUE_P (table) && UINT8_VALUE_P (value))
1104         {
1105           table = make_uint8_byte_table (UINT8_ENCODE (table));
1106           XUINT8_BYTE_TABLE(table)->property[idx] = UINT8_ENCODE (value);
1107         }
1108       else if (UINT16_VALUE_P (table) && UINT16_VALUE_P (value))
1109         {
1110           table = make_uint16_byte_table (UINT16_ENCODE (table));
1111           XUINT16_BYTE_TABLE(table)->property[idx] = UINT16_ENCODE (value);
1112         }
1113       else
1114         {
1115           table = make_byte_table (table);
1116           XBYTE_TABLE(table)->property[idx] = value;
1117         }
1118     }
1119   return table;
1120 }
1121
1122
1123 Lisp_Object
1124 make_char_id_table (Lisp_Object initval)
1125 {
1126   Lisp_Object obj;
1127   obj = Fmake_char_table (Qgeneric);
1128   fill_char_table (XCHAR_TABLE (obj), initval);
1129   return obj;
1130 }
1131
1132
1133 #if defined(HAVE_CHISE) && !defined(HAVE_LIBCHISE_LIBCHISE)
1134 Lisp_Object Qsystem_char_id;
1135 #endif
1136
1137 Lisp_Object Qcomposition;
1138 Lisp_Object Q_decomposition;
1139 Lisp_Object Q_identical;
1140 Lisp_Object Q_identical_from;
1141 Lisp_Object Q_denotational;
1142 Lisp_Object Q_denotational_from;
1143 Lisp_Object Q_subsumptive;
1144 Lisp_Object Q_subsumptive_from;
1145 Lisp_Object Q_component;
1146 Lisp_Object Q_component_of;
1147 Lisp_Object Q_same;
1148 Lisp_Object Q_same_of;
1149 Lisp_Object Qto_ucs;
1150 Lisp_Object Q_ucs_unified;
1151 Lisp_Object Qcompat;
1152 Lisp_Object Qisolated;
1153 Lisp_Object Qinitial;
1154 Lisp_Object Qmedial;
1155 Lisp_Object Qfinal;
1156 Lisp_Object Qvertical;
1157 Lisp_Object QnoBreak;
1158 Lisp_Object Qfraction;
1159 Lisp_Object Qsuper;
1160 Lisp_Object Qsub;
1161 Lisp_Object Qcircle;
1162 Lisp_Object Qsquare;
1163 Lisp_Object Qwide;
1164 Lisp_Object Qnarrow;
1165 Lisp_Object Qsmall;
1166 Lisp_Object Qfont;
1167
1168 Emchar to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg);
1169
1170 Emchar
1171 to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg)
1172 {
1173   if (INTP (v))
1174     return XINT (v);
1175   if (CHARP (v))
1176     return XCHAR (v);
1177   else if (EQ (v, Qcompat))
1178     return -1;
1179   else if (EQ (v, Qisolated))
1180     return -2;
1181   else if (EQ (v, Qinitial))
1182     return -3;
1183   else if (EQ (v, Qmedial))
1184     return -4;
1185   else if (EQ (v, Qfinal))
1186     return -5;
1187   else if (EQ (v, Qvertical))
1188     return -6;
1189   else if (EQ (v, QnoBreak))
1190     return -7;
1191   else if (EQ (v, Qfraction))
1192     return -8;
1193   else if (EQ (v, Qsuper))
1194     return -9;
1195   else if (EQ (v, Qsub))
1196     return -10;
1197   else if (EQ (v, Qcircle))
1198     return -11;
1199   else if (EQ (v, Qsquare))
1200     return -12;
1201   else if (EQ (v, Qwide))
1202     return -13;
1203   else if (EQ (v, Qnarrow))
1204     return -14;
1205   else if (EQ (v, Qsmall))
1206     return -15;
1207   else if (EQ (v, Qfont))
1208     return -16;
1209   else 
1210     signal_simple_error (err_msg, err_arg);
1211 }
1212
1213 DEFUN ("get-composite-char", Fget_composite_char, 1, 1, 0, /*
1214 Return character corresponding with list.
1215 */
1216        (list))
1217 {
1218   Lisp_Object base, modifier;
1219   Lisp_Object rest;
1220
1221   if (!CONSP (list))
1222     signal_simple_error ("Invalid value for composition", list);
1223   base = Fcar (list);
1224   rest = Fcdr (list);
1225   while (!NILP (rest))
1226     {
1227       if (!CHARP (base))
1228         return Qnil;
1229       if (!CONSP (rest))
1230         signal_simple_error ("Invalid value for composition", list);
1231       modifier = Fcar (rest);
1232       rest = Fcdr (rest);
1233       base = Fcdr (Fassq (modifier,
1234                           Fchar_feature (base, Qcomposition, Qnil,
1235                                          Qnil, Qnil)));
1236     }
1237   return base;
1238 }
1239
1240 DEFUN ("char-variants", Fchar_variants, 1, 1, 0, /*
1241 Return variants of CHARACTER.
1242 */
1243        (character))
1244 {
1245   Lisp_Object ret;
1246
1247   CHECK_CHAR (character);
1248   ret = Fchar_feature (character, Q_ucs_unified, Qnil,
1249                        Qnil, Qnil);
1250   if (CONSP (ret))
1251     return Fcopy_list (ret);
1252   else
1253     return Qnil;
1254 }
1255
1256 #endif
1257
1258 \f
1259 /* A char table maps from ranges of characters to values.
1260
1261    Implementing a general data structure that maps from arbitrary
1262    ranges of numbers to values is tricky to do efficiently.  As it
1263    happens, it should suffice (and is usually more convenient, anyway)
1264    when dealing with characters to restrict the sorts of ranges that
1265    can be assigned values, as follows:
1266
1267    1) All characters.
1268    2) All characters in a charset.
1269    3) All characters in a particular row of a charset, where a "row"
1270       means all characters with the same first byte.
1271    4) A particular character in a charset.
1272
1273    We use char tables to generalize the 256-element vectors now
1274    littering the Emacs code.
1275
1276    Possible uses (all should be converted at some point):
1277
1278    1) category tables
1279    2) syntax tables
1280    3) display tables
1281    4) case tables
1282    5) keyboard-translate-table?
1283
1284    We provide an
1285    abstract type to generalize the Emacs vectors and Mule
1286    vectors-of-vectors goo.
1287    */
1288
1289 /************************************************************************/
1290 /*                         Char Table object                            */
1291 /************************************************************************/
1292
1293 #if defined(MULE)&&!defined(UTF2000)
1294
1295 static Lisp_Object
1296 mark_char_table_entry (Lisp_Object obj)
1297 {
1298   Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (obj);
1299   int i;
1300
1301   for (i = 0; i < 96; i++)
1302     {
1303       mark_object (cte->level2[i]);
1304     }
1305   return Qnil;
1306 }
1307
1308 static int
1309 char_table_entry_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
1310 {
1311   Lisp_Char_Table_Entry *cte1 = XCHAR_TABLE_ENTRY (obj1);
1312   Lisp_Char_Table_Entry *cte2 = XCHAR_TABLE_ENTRY (obj2);
1313   int i;
1314
1315   for (i = 0; i < 96; i++)
1316     if (!internal_equal (cte1->level2[i], cte2->level2[i], depth + 1))
1317       return 0;
1318
1319   return 1;
1320 }
1321
1322 static unsigned long
1323 char_table_entry_hash (Lisp_Object obj, int depth)
1324 {
1325   Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (obj);
1326
1327   return internal_array_hash (cte->level2, 96, depth);
1328 }
1329
1330 static const struct lrecord_description char_table_entry_description[] = {
1331   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Char_Table_Entry, level2), 96 },
1332   { XD_END }
1333 };
1334
1335 DEFINE_LRECORD_IMPLEMENTATION ("char-table-entry", char_table_entry,
1336                                mark_char_table_entry, internal_object_printer,
1337                                0, char_table_entry_equal,
1338                                char_table_entry_hash,
1339                                char_table_entry_description,
1340                                Lisp_Char_Table_Entry);
1341 #endif /* MULE */
1342
1343 static Lisp_Object
1344 mark_char_table (Lisp_Object obj)
1345 {
1346   Lisp_Char_Table *ct = XCHAR_TABLE (obj);
1347 #ifdef UTF2000
1348
1349   mark_object (ct->table);
1350   mark_object (ct->name);
1351 #ifndef HAVE_LIBCHISE
1352   mark_object (ct->db);
1353 #endif
1354 #else
1355   int i;
1356
1357   for (i = 0; i < NUM_ASCII_CHARS; i++)
1358     mark_object (ct->ascii[i]);
1359 #ifdef MULE
1360   for (i = 0; i < NUM_LEADING_BYTES; i++)
1361     mark_object (ct->level1[i]);
1362 #endif
1363 #endif
1364 #ifdef UTF2000
1365   return ct->default_value;
1366 #else
1367   return ct->mirror_table;
1368 #endif
1369 }
1370
1371 /* WARNING: All functions of this nature need to be written extremely
1372    carefully to avoid crashes during GC.  Cf. prune_specifiers()
1373    and prune_weak_hash_tables(). */
1374
1375 void
1376 prune_syntax_tables (void)
1377 {
1378   Lisp_Object rest, prev = Qnil;
1379
1380   for (rest = Vall_syntax_tables;
1381        !NILP (rest);
1382        rest = XCHAR_TABLE (rest)->next_table)
1383     {
1384       if (! marked_p (rest))
1385         {
1386           /* This table is garbage.  Remove it from the list. */
1387           if (NILP (prev))
1388             Vall_syntax_tables = XCHAR_TABLE (rest)->next_table;
1389           else
1390             XCHAR_TABLE (prev)->next_table =
1391               XCHAR_TABLE (rest)->next_table;
1392         }
1393     }
1394 }
1395
1396 static Lisp_Object
1397 char_table_type_to_symbol (enum char_table_type type)
1398 {
1399   switch (type)
1400   {
1401   default: abort();
1402   case CHAR_TABLE_TYPE_GENERIC:  return Qgeneric;
1403   case CHAR_TABLE_TYPE_SYNTAX:   return Qsyntax;
1404   case CHAR_TABLE_TYPE_DISPLAY:  return Qdisplay;
1405   case CHAR_TABLE_TYPE_CHAR:     return Qchar;
1406 #ifdef MULE
1407   case CHAR_TABLE_TYPE_CATEGORY: return Qcategory;
1408 #endif
1409   }
1410 }
1411
1412 static enum char_table_type
1413 symbol_to_char_table_type (Lisp_Object symbol)
1414 {
1415   CHECK_SYMBOL (symbol);
1416
1417   if (EQ (symbol, Qgeneric))  return CHAR_TABLE_TYPE_GENERIC;
1418   if (EQ (symbol, Qsyntax))   return CHAR_TABLE_TYPE_SYNTAX;
1419   if (EQ (symbol, Qdisplay))  return CHAR_TABLE_TYPE_DISPLAY;
1420   if (EQ (symbol, Qchar))     return CHAR_TABLE_TYPE_CHAR;
1421 #ifdef MULE
1422   if (EQ (symbol, Qcategory)) return CHAR_TABLE_TYPE_CATEGORY;
1423 #endif
1424
1425   signal_simple_error ("Unrecognized char table type", symbol);
1426   return CHAR_TABLE_TYPE_GENERIC; /* not reached */
1427 }
1428
1429 #ifndef UTF2000
1430 static void
1431 print_chartab_range (Emchar first, Emchar last, Lisp_Object val,
1432                      Lisp_Object printcharfun)
1433 {
1434   if (first != last)
1435     {
1436       write_c_string (" (", printcharfun);
1437       print_internal (make_char (first), printcharfun, 0);
1438       write_c_string (" ", printcharfun);
1439       print_internal (make_char (last), printcharfun, 0);
1440       write_c_string (") ", printcharfun);
1441     }
1442   else
1443     {
1444       write_c_string (" ", printcharfun);
1445       print_internal (make_char (first), printcharfun, 0);
1446       write_c_string (" ", printcharfun);
1447     }
1448   print_internal (val, printcharfun, 1);
1449 }
1450 #endif
1451
1452 #if defined(MULE)&&!defined(UTF2000)
1453
1454 static void
1455 print_chartab_charset_row (Lisp_Object charset,
1456                            int row,
1457                            Lisp_Char_Table_Entry *cte,
1458                            Lisp_Object printcharfun)
1459 {
1460   int i;
1461   Lisp_Object cat = Qunbound;
1462   int first = -1;
1463
1464   for (i = 32; i < 128; i++)
1465     {
1466       Lisp_Object pam = cte->level2[i - 32];
1467
1468       if (first == -1)
1469         {
1470           first = i;
1471           cat = pam;
1472           continue;
1473         }
1474
1475       if (!EQ (cat, pam))
1476         {
1477           if (row == -1)
1478             print_chartab_range (MAKE_CHAR (charset, first, 0),
1479                                  MAKE_CHAR (charset, i - 1, 0),
1480                                  cat, printcharfun);
1481           else
1482             print_chartab_range (MAKE_CHAR (charset, row, first),
1483                                  MAKE_CHAR (charset, row, i - 1),
1484                                  cat, printcharfun);
1485           first = -1;
1486           i--;
1487         }
1488     }
1489
1490   if (first != -1)
1491     {
1492       if (row == -1)
1493         print_chartab_range (MAKE_CHAR (charset, first, 0),
1494                              MAKE_CHAR (charset, i - 1, 0),
1495                              cat, printcharfun);
1496       else
1497         print_chartab_range (MAKE_CHAR (charset, row, first),
1498                              MAKE_CHAR (charset, row, i - 1),
1499                              cat, printcharfun);
1500     }
1501 }
1502
1503 static void
1504 print_chartab_two_byte_charset (Lisp_Object charset,
1505                                 Lisp_Char_Table_Entry *cte,
1506                                 Lisp_Object printcharfun)
1507 {
1508   int i;
1509
1510   for (i = 32; i < 128; i++)
1511     {
1512       Lisp_Object jen = cte->level2[i - 32];
1513
1514       if (!CHAR_TABLE_ENTRYP (jen))
1515         {
1516           char buf[100];
1517
1518           write_c_string (" [", printcharfun);
1519           print_internal (XCHARSET_NAME (charset), printcharfun, 0);
1520           sprintf (buf, " %d] ", i);
1521           write_c_string (buf, printcharfun);
1522           print_internal (jen, printcharfun, 0);
1523         }
1524       else
1525         print_chartab_charset_row (charset, i, XCHAR_TABLE_ENTRY (jen),
1526                                    printcharfun);
1527     }
1528 }
1529
1530 #endif /* MULE */
1531
1532 static void
1533 print_char_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
1534 {
1535   Lisp_Char_Table *ct = XCHAR_TABLE (obj);
1536 #ifdef UTF2000
1537   int i;
1538   struct gcpro gcpro1, gcpro2;
1539   GCPRO2 (obj, printcharfun);
1540
1541   write_c_string ("#s(char-table ", printcharfun);
1542   write_c_string (" ", printcharfun);
1543   write_c_string (string_data
1544                   (symbol_name
1545                    (XSYMBOL (char_table_type_to_symbol (ct->type)))),
1546                   printcharfun);
1547   write_c_string ("\n ", printcharfun);
1548   print_internal (ct->default_value, printcharfun, escapeflag);
1549   for (i = 0; i < 256; i++)
1550     {
1551       Lisp_Object elt = get_byte_table (ct->table, i);
1552       if (i != 0) write_c_string ("\n  ", printcharfun);
1553       if (EQ (elt, Qunbound))
1554         write_c_string ("void", printcharfun);
1555       else
1556         print_internal (elt, printcharfun, escapeflag);
1557     }
1558   UNGCPRO;
1559 #else /* non UTF2000 */
1560   char buf[200];
1561
1562   sprintf (buf, "#s(char-table type %s data (",
1563            string_data (symbol_name (XSYMBOL
1564                                      (char_table_type_to_symbol (ct->type)))));
1565   write_c_string (buf, printcharfun);
1566
1567   /* Now write out the ASCII/Control-1 stuff. */
1568   {
1569     int i;
1570     int first = -1;
1571     Lisp_Object val = Qunbound;
1572
1573     for (i = 0; i < NUM_ASCII_CHARS; i++)
1574       {
1575         if (first == -1)
1576           {
1577             first = i;
1578             val = ct->ascii[i];
1579             continue;
1580           }
1581
1582         if (!EQ (ct->ascii[i], val))
1583           {
1584             print_chartab_range (first, i - 1, val, printcharfun);
1585             first = -1;
1586             i--;
1587           }
1588       }
1589
1590     if (first != -1)
1591       print_chartab_range (first, i - 1, val, printcharfun);
1592   }
1593
1594 #ifdef MULE
1595   {
1596     Charset_ID i;
1597
1598     for (i = MIN_LEADING_BYTE; i < MIN_LEADING_BYTE + NUM_LEADING_BYTES;
1599          i++)
1600       {
1601         Lisp_Object ann = ct->level1[i - MIN_LEADING_BYTE];
1602         Lisp_Object charset = CHARSET_BY_LEADING_BYTE (i);
1603
1604         if (!CHARSETP (charset) || i == LEADING_BYTE_ASCII
1605             || i == LEADING_BYTE_CONTROL_1)
1606           continue;
1607         if (!CHAR_TABLE_ENTRYP (ann))
1608           {
1609             write_c_string (" ", printcharfun);
1610             print_internal (XCHARSET_NAME (charset),
1611                             printcharfun, 0);
1612             write_c_string (" ", printcharfun);
1613             print_internal (ann, printcharfun, 0);
1614           }
1615         else
1616           {
1617             Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (ann);
1618             if (XCHARSET_DIMENSION (charset) == 1)
1619               print_chartab_charset_row (charset, -1, cte, printcharfun);
1620             else
1621               print_chartab_two_byte_charset (charset, cte, printcharfun);
1622           }
1623       }
1624   }
1625 #endif /* MULE */
1626 #endif /* non UTF2000 */
1627
1628   write_c_string ("))", printcharfun);
1629 }
1630
1631 static int
1632 char_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
1633 {
1634   Lisp_Char_Table *ct1 = XCHAR_TABLE (obj1);
1635   Lisp_Char_Table *ct2 = XCHAR_TABLE (obj2);
1636   int i;
1637
1638   if (CHAR_TABLE_TYPE (ct1) != CHAR_TABLE_TYPE (ct2))
1639     return 0;
1640
1641 #ifdef UTF2000
1642   for (i = 0; i < 256; i++)
1643     {
1644       if (!internal_equal (get_byte_table (ct1->table, i),
1645                            get_byte_table (ct2->table, i), 0))
1646         return 0;
1647     }
1648 #else
1649   for (i = 0; i < NUM_ASCII_CHARS; i++)
1650     if (!internal_equal (ct1->ascii[i], ct2->ascii[i], depth + 1))
1651       return 0;
1652
1653 #ifdef MULE
1654   for (i = 0; i < NUM_LEADING_BYTES; i++)
1655     if (!internal_equal (ct1->level1[i], ct2->level1[i], depth + 1))
1656       return 0;
1657 #endif /* MULE */
1658 #endif /* non UTF2000 */
1659
1660   return 1;
1661 }
1662
1663 static unsigned long
1664 char_table_hash (Lisp_Object obj, int depth)
1665 {
1666   Lisp_Char_Table *ct = XCHAR_TABLE (obj);
1667 #ifdef UTF2000
1668     return byte_table_hash (ct->table, depth + 1);
1669 #else
1670   unsigned long hashval = internal_array_hash (ct->ascii, NUM_ASCII_CHARS,
1671                                                depth);
1672 #ifdef MULE
1673   hashval = HASH2 (hashval,
1674                    internal_array_hash (ct->level1, NUM_LEADING_BYTES, depth));
1675 #endif /* MULE */
1676   return hashval;
1677 #endif
1678 }
1679
1680 static const struct lrecord_description char_table_description[] = {
1681 #ifdef UTF2000
1682   { XD_LISP_OBJECT, offsetof(Lisp_Char_Table, table) },
1683   { XD_LISP_OBJECT, offsetof(Lisp_Char_Table, default_value) },
1684   { XD_LISP_OBJECT, offsetof(Lisp_Char_Table, name) },
1685 #ifndef HAVE_LIBCHISE
1686   { XD_LISP_OBJECT, offsetof(Lisp_Char_Table, db) },
1687 #endif
1688 #else
1689   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Char_Table, ascii), NUM_ASCII_CHARS },
1690 #ifdef MULE
1691   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Char_Table, level1), NUM_LEADING_BYTES },
1692 #endif
1693 #endif
1694 #ifndef UTF2000
1695   { XD_LISP_OBJECT, offsetof (Lisp_Char_Table, mirror_table) },
1696 #endif
1697   { XD_LO_LINK,     offsetof (Lisp_Char_Table, next_table) },
1698   { XD_END }
1699 };
1700
1701 DEFINE_LRECORD_IMPLEMENTATION ("char-table", char_table,
1702                                mark_char_table, print_char_table, 0,
1703                                char_table_equal, char_table_hash,
1704                                char_table_description,
1705                                Lisp_Char_Table);
1706
1707 DEFUN ("char-table-p", Fchar_table_p, 1, 1, 0, /*
1708 Return non-nil if OBJECT is a char table.
1709
1710 A char table is a table that maps characters (or ranges of characters)
1711 to values.  Char tables are specialized for characters, only allowing
1712 particular sorts of ranges to be assigned values.  Although this
1713 loses in generality, it makes for extremely fast (constant-time)
1714 lookups, and thus is feasible for applications that do an extremely
1715 large number of lookups (e.g. scanning a buffer for a character in
1716 a particular syntax, where a lookup in the syntax table must occur
1717 once per character).
1718
1719 When Mule support exists, the types of ranges that can be assigned
1720 values are
1721
1722 -- all characters
1723 -- an entire charset
1724 -- a single row in a two-octet charset
1725 -- a single character
1726
1727 When Mule support is not present, the types of ranges that can be
1728 assigned values are
1729
1730 -- all characters
1731 -- a single character
1732
1733 To create a char table, use `make-char-table'.
1734 To modify a char table, use `put-char-table' or `remove-char-table'.
1735 To retrieve the value for a particular character, use `get-char-table'.
1736 See also `map-char-table', `clear-char-table', `copy-char-table',
1737 `valid-char-table-type-p', `char-table-type-list',
1738 `valid-char-table-value-p', and `check-char-table-value'.
1739 */
1740        (object))
1741 {
1742   return CHAR_TABLEP (object) ? Qt : Qnil;
1743 }
1744
1745 DEFUN ("char-table-type-list", Fchar_table_type_list, 0, 0, 0, /*
1746 Return a list of the recognized char table types.
1747 See `valid-char-table-type-p'.
1748 */
1749        ())
1750 {
1751 #ifdef MULE
1752   return list5 (Qchar, Qcategory, Qdisplay, Qgeneric, Qsyntax);
1753 #else
1754   return list4 (Qchar, Qdisplay, Qgeneric, Qsyntax);
1755 #endif
1756 }
1757
1758 DEFUN ("valid-char-table-type-p", Fvalid_char_table_type_p, 1, 1, 0, /*
1759 Return t if TYPE if a recognized char table type.
1760
1761 Each char table type is used for a different purpose and allows different
1762 sorts of values.  The different char table types are
1763
1764 `category'
1765         Used for category tables, which specify the regexp categories
1766         that a character is in.  The valid values are nil or a
1767         bit vector of 95 elements.  Higher-level Lisp functions are
1768         provided for working with category tables.  Currently categories
1769         and category tables only exist when Mule support is present.
1770 `char'
1771         A generalized char table, for mapping from one character to
1772         another.  Used for case tables, syntax matching tables,
1773         `keyboard-translate-table', etc.  The valid values are characters.
1774 `generic'
1775         An even more generalized char table, for mapping from a
1776         character to anything.
1777 `display'
1778         Used for display tables, which specify how a particular character
1779         is to appear when displayed.  #### Not yet implemented.
1780 `syntax'
1781         Used for syntax tables, which specify the syntax of a particular
1782         character.  Higher-level Lisp functions are provided for
1783         working with syntax tables.  The valid values are integers.
1784
1785 */
1786        (type))
1787 {
1788   return (EQ (type, Qchar)     ||
1789 #ifdef MULE
1790           EQ (type, Qcategory) ||
1791 #endif
1792           EQ (type, Qdisplay)  ||
1793           EQ (type, Qgeneric)  ||
1794           EQ (type, Qsyntax)) ? Qt : Qnil;
1795 }
1796
1797 DEFUN ("char-table-type", Fchar_table_type, 1, 1, 0, /*
1798 Return the type of CHAR-TABLE.
1799 See `valid-char-table-type-p'.
1800 */
1801        (char_table))
1802 {
1803   CHECK_CHAR_TABLE (char_table);
1804   return char_table_type_to_symbol (XCHAR_TABLE (char_table)->type);
1805 }
1806
1807 void
1808 fill_char_table (Lisp_Char_Table *ct, Lisp_Object value)
1809 {
1810 #ifdef UTF2000
1811   ct->table = Qunbound;
1812   ct->default_value = value;
1813   ct->unloaded = 0;
1814 #else
1815   int i;
1816
1817   for (i = 0; i < NUM_ASCII_CHARS; i++)
1818     ct->ascii[i] = value;
1819 #ifdef MULE
1820   for (i = 0; i < NUM_LEADING_BYTES; i++)
1821     ct->level1[i] = value;
1822 #endif /* MULE */
1823 #endif
1824
1825 #ifndef UTF2000
1826   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
1827     update_syntax_table (ct);
1828 #endif
1829 }
1830
1831 DEFUN ("reset-char-table", Freset_char_table, 1, 1, 0, /*
1832 Reset CHAR-TABLE to its default state.
1833 */
1834        (char_table))
1835 {
1836   Lisp_Char_Table *ct;
1837
1838   CHECK_CHAR_TABLE (char_table);
1839   ct = XCHAR_TABLE (char_table);
1840
1841   switch (ct->type)
1842     {
1843     case CHAR_TABLE_TYPE_CHAR:
1844       fill_char_table (ct, make_char (0));
1845       break;
1846     case CHAR_TABLE_TYPE_DISPLAY:
1847     case CHAR_TABLE_TYPE_GENERIC:
1848 #ifdef MULE
1849     case CHAR_TABLE_TYPE_CATEGORY:
1850 #endif /* MULE */
1851       fill_char_table (ct, Qnil);
1852       break;
1853
1854     case CHAR_TABLE_TYPE_SYNTAX:
1855       fill_char_table (ct, make_int (Sinherit));
1856       break;
1857
1858     default:
1859       abort ();
1860     }
1861
1862   return Qnil;
1863 }
1864
1865 DEFUN ("make-char-table", Fmake_char_table, 1, 1, 0, /*
1866 Return a new, empty char table of type TYPE.
1867 Currently recognized types are 'char, 'category, 'display, 'generic,
1868 and 'syntax.  See `valid-char-table-type-p'.
1869 */
1870        (type))
1871 {
1872   Lisp_Char_Table *ct;
1873   Lisp_Object obj;
1874   enum char_table_type ty = symbol_to_char_table_type (type);
1875
1876   ct = alloc_lcrecord_type (Lisp_Char_Table, &lrecord_char_table);
1877   ct->type = ty;
1878 #ifndef UTF2000
1879   if (ty == CHAR_TABLE_TYPE_SYNTAX)
1880     {
1881       ct->mirror_table = Fmake_char_table (Qgeneric);
1882       fill_char_table (XCHAR_TABLE (ct->mirror_table),
1883                        make_int (Spunct));
1884     }
1885   else
1886     ct->mirror_table = Qnil;
1887 #else
1888   ct->name = Qnil;
1889 #ifndef HAVE_LIBCHISE
1890   ct->db = Qnil;
1891 #endif
1892 #endif
1893   ct->next_table = Qnil;
1894   XSETCHAR_TABLE (obj, ct);
1895   if (ty == CHAR_TABLE_TYPE_SYNTAX)
1896     {
1897       ct->next_table = Vall_syntax_tables;
1898       Vall_syntax_tables = obj;
1899     }
1900   Freset_char_table (obj);
1901   return obj;
1902 }
1903
1904 #if defined(MULE)&&!defined(UTF2000)
1905
1906 static Lisp_Object
1907 make_char_table_entry (Lisp_Object initval)
1908 {
1909   Lisp_Object obj;
1910   int i;
1911   Lisp_Char_Table_Entry *cte =
1912     alloc_lcrecord_type (Lisp_Char_Table_Entry, &lrecord_char_table_entry);
1913
1914   for (i = 0; i < 96; i++)
1915     cte->level2[i] = initval;
1916
1917   XSETCHAR_TABLE_ENTRY (obj, cte);
1918   return obj;
1919 }
1920
1921 static Lisp_Object
1922 copy_char_table_entry (Lisp_Object entry)
1923 {
1924   Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (entry);
1925   Lisp_Object obj;
1926   int i;
1927   Lisp_Char_Table_Entry *ctenew =
1928     alloc_lcrecord_type (Lisp_Char_Table_Entry, &lrecord_char_table_entry);
1929
1930   for (i = 0; i < 96; i++)
1931     {
1932       Lisp_Object new = cte->level2[i];
1933       if (CHAR_TABLE_ENTRYP (new))
1934         ctenew->level2[i] = copy_char_table_entry (new);
1935       else
1936         ctenew->level2[i] = new;
1937     }
1938
1939   XSETCHAR_TABLE_ENTRY (obj, ctenew);
1940   return obj;
1941 }
1942
1943 #endif /* MULE */
1944
1945 DEFUN ("copy-char-table", Fcopy_char_table, 1, 1, 0, /*
1946 Return a new char table which is a copy of CHAR-TABLE.
1947 It will contain the same values for the same characters and ranges
1948 as CHAR-TABLE.  The values will not themselves be copied.
1949 */
1950        (char_table))
1951 {
1952   Lisp_Char_Table *ct, *ctnew;
1953   Lisp_Object obj;
1954 #ifndef UTF2000
1955   int i;
1956 #endif
1957
1958   CHECK_CHAR_TABLE (char_table);
1959   ct = XCHAR_TABLE (char_table);
1960   ctnew = alloc_lcrecord_type (Lisp_Char_Table, &lrecord_char_table);
1961   ctnew->type = ct->type;
1962 #ifdef UTF2000
1963   ctnew->default_value = ct->default_value;
1964   /* [tomo:2002-01-21] Perhaps this code seems wrong */
1965   ctnew->name = ct->name;
1966 #ifndef HAVE_LIBCHISE
1967   ctnew->db = ct->db;
1968 #endif
1969
1970   if (UINT8_BYTE_TABLE_P (ct->table))
1971     {
1972       ctnew->table = copy_uint8_byte_table (ct->table);
1973     }
1974   else if (UINT16_BYTE_TABLE_P (ct->table))
1975     {
1976       ctnew->table = copy_uint16_byte_table (ct->table);
1977     }
1978   else if (BYTE_TABLE_P (ct->table))
1979     {
1980       ctnew->table = copy_byte_table (ct->table);
1981     }
1982   else if (!UNBOUNDP (ct->table))
1983     ctnew->table = ct->table;
1984 #else /* non UTF2000 */
1985
1986   for (i = 0; i < NUM_ASCII_CHARS; i++)
1987     {
1988       Lisp_Object new = ct->ascii[i];
1989 #ifdef MULE
1990       assert (! (CHAR_TABLE_ENTRYP (new)));
1991 #endif /* MULE */
1992       ctnew->ascii[i] = new;
1993     }
1994
1995 #ifdef MULE
1996
1997   for (i = 0; i < NUM_LEADING_BYTES; i++)
1998     {
1999       Lisp_Object new = ct->level1[i];
2000       if (CHAR_TABLE_ENTRYP (new))
2001         ctnew->level1[i] = copy_char_table_entry (new);
2002       else
2003         ctnew->level1[i] = new;
2004     }
2005
2006 #endif /* MULE */
2007 #endif /* non UTF2000 */
2008
2009 #ifndef UTF2000
2010   if (CHAR_TABLEP (ct->mirror_table))
2011     ctnew->mirror_table = Fcopy_char_table (ct->mirror_table);
2012   else
2013     ctnew->mirror_table = ct->mirror_table;
2014 #endif
2015   ctnew->next_table = Qnil;
2016   XSETCHAR_TABLE (obj, ctnew);
2017   if (ctnew->type == CHAR_TABLE_TYPE_SYNTAX)
2018     {
2019       ctnew->next_table = Vall_syntax_tables;
2020       Vall_syntax_tables = obj;
2021     }
2022   return obj;
2023 }
2024
2025 INLINE_HEADER int XCHARSET_CELL_RANGE (Lisp_Object ccs);
2026 INLINE_HEADER int
2027 XCHARSET_CELL_RANGE (Lisp_Object ccs)
2028 {
2029   switch (XCHARSET_CHARS (ccs))
2030     {
2031     case 94:
2032       return (33 << 8) | 126;
2033     case 96:
2034       return (32 << 8) | 127;
2035 #ifdef UTF2000
2036     case 128:
2037       return (0 << 8) | 127;
2038     case 256:
2039       return (0 << 8) | 255;
2040 #endif
2041     default:
2042       abort ();
2043       return 0;
2044     }
2045 }
2046
2047 #ifndef UTF2000
2048 static
2049 #endif
2050 void
2051 decode_char_table_range (Lisp_Object range, struct chartab_range *outrange)
2052 {
2053   if (EQ (range, Qt))
2054     outrange->type = CHARTAB_RANGE_ALL;
2055 #ifdef UTF2000
2056   else if (EQ (range, Qnil))
2057     outrange->type = CHARTAB_RANGE_DEFAULT;
2058 #endif
2059   else if (CHAR_OR_CHAR_INTP (range))
2060     {
2061       outrange->type = CHARTAB_RANGE_CHAR;
2062       outrange->ch = XCHAR_OR_CHAR_INT (range);
2063     }
2064 #ifndef MULE
2065   else
2066     signal_simple_error ("Range must be t or a character", range);
2067 #else /* MULE */
2068   else if (VECTORP (range))
2069     {
2070       Lisp_Vector *vec = XVECTOR (range);
2071       Lisp_Object *elts = vector_data (vec);
2072       int cell_min, cell_max;
2073
2074       outrange->type = CHARTAB_RANGE_ROW;
2075       outrange->charset = Fget_charset (elts[0]);
2076       CHECK_INT (elts[1]);
2077       outrange->row = XINT (elts[1]);
2078       if (XCHARSET_DIMENSION (outrange->charset) < 2)
2079         signal_simple_error ("Charset in row vector must be multi-byte",
2080                              outrange->charset);
2081       else
2082         {
2083           int ret = XCHARSET_CELL_RANGE (outrange->charset);
2084
2085           cell_min = ret >> 8;
2086           cell_max = ret & 0xFF;
2087         }
2088       if (XCHARSET_DIMENSION (outrange->charset) == 2)
2089         check_int_range (outrange->row, cell_min, cell_max);
2090 #ifdef UTF2000
2091       else if (XCHARSET_DIMENSION (outrange->charset) == 3)
2092         {
2093           check_int_range (outrange->row >> 8  , cell_min, cell_max);
2094           check_int_range (outrange->row & 0xFF, cell_min, cell_max);
2095         }
2096       else if (XCHARSET_DIMENSION (outrange->charset) == 4)
2097         {
2098           check_int_range ( outrange->row >> 16       , cell_min, cell_max);
2099           check_int_range ((outrange->row >> 8) & 0xFF, cell_min, cell_max);
2100           check_int_range ( outrange->row       & 0xFF, cell_min, cell_max);
2101         }
2102 #endif
2103       else
2104         abort ();
2105     }
2106   else
2107     {
2108       if (!CHARSETP (range) && !SYMBOLP (range))
2109         signal_simple_error
2110           ("Char table range must be t, charset, char, or vector", range);
2111       outrange->type = CHARTAB_RANGE_CHARSET;
2112       outrange->charset = Fget_charset (range);
2113     }
2114 #endif /* MULE */
2115 }
2116
2117 #if defined(MULE)&&!defined(UTF2000)
2118
2119 /* called from CHAR_TABLE_VALUE(). */
2120 Lisp_Object
2121 get_non_ascii_char_table_value (Lisp_Char_Table *ct, Charset_ID leading_byte,
2122                                Emchar c)
2123 {
2124   Lisp_Object val;
2125 #ifdef UTF2000
2126   Lisp_Object charset;
2127 #else
2128   Lisp_Object charset = CHARSET_BY_LEADING_BYTE (leading_byte);
2129 #endif
2130   int byte1, byte2;
2131
2132 #ifdef UTF2000
2133   BREAKUP_CHAR (c, charset, byte1, byte2);
2134 #else
2135   BREAKUP_CHAR_1_UNSAFE (c, charset, byte1, byte2);
2136 #endif
2137   val = ct->level1[leading_byte - MIN_LEADING_BYTE];
2138   if (CHAR_TABLE_ENTRYP (val))
2139     {
2140       Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (val);
2141       val = cte->level2[byte1 - 32];
2142       if (CHAR_TABLE_ENTRYP (val))
2143         {
2144           cte = XCHAR_TABLE_ENTRY (val);
2145           assert (byte2 >= 32);
2146           val = cte->level2[byte2 - 32];
2147           assert (!CHAR_TABLE_ENTRYP (val));
2148         }
2149     }
2150
2151   return val;
2152 }
2153
2154 #endif /* MULE */
2155
2156 Lisp_Object
2157 get_char_table (Emchar ch, Lisp_Char_Table *ct)
2158 {
2159 #ifdef UTF2000
2160   {
2161     Lisp_Object ret = get_char_id_table (ct, ch);
2162
2163 #ifdef HAVE_CHISE
2164     if (NILP (ret))
2165       {
2166         if (EQ (CHAR_TABLE_NAME (ct), Qdowncase))
2167           ret = Fchar_feature (make_char (ch), Q_lowercase, Qnil,
2168                                Qnil, Qnil);
2169         else if (EQ (CHAR_TABLE_NAME (ct), Qflippedcase))
2170           ret = Fchar_feature (make_char (ch), Q_uppercase, Qnil,
2171                                Qnil, Qnil);
2172         if (CONSP (ret))
2173           {
2174             ret = XCAR (ret);
2175             if (CONSP (ret))
2176               ret = Ffind_char (ret);
2177           }
2178       }
2179 #endif
2180     return ret;
2181   }
2182 #elif defined(MULE)
2183   {
2184     Lisp_Object charset;
2185     int byte1, byte2;
2186     Lisp_Object val;
2187
2188     BREAKUP_CHAR (ch, charset, byte1, byte2);
2189
2190     if (EQ (charset, Vcharset_ascii))
2191       val = ct->ascii[byte1];
2192     else if (EQ (charset, Vcharset_control_1))
2193       val = ct->ascii[byte1 + 128];
2194     else
2195       {
2196         int lb = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE;
2197         val = ct->level1[lb];
2198         if (CHAR_TABLE_ENTRYP (val))
2199           {
2200             Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (val);
2201             val = cte->level2[byte1 - 32];
2202             if (CHAR_TABLE_ENTRYP (val))
2203               {
2204                 cte = XCHAR_TABLE_ENTRY (val);
2205                 assert (byte2 >= 32);
2206                 val = cte->level2[byte2 - 32];
2207                 assert (!CHAR_TABLE_ENTRYP (val));
2208               }
2209           }
2210       }
2211
2212     return val;
2213   }
2214 #else /* not MULE */
2215   return ct->ascii[(unsigned char)ch];
2216 #endif /* not MULE */
2217 }
2218
2219
2220 DEFUN ("get-char-table", Fget_char_table, 2, 2, 0, /*
2221 Find value for CHARACTER in CHAR-TABLE.
2222 */
2223        (character, char_table))
2224 {
2225   CHECK_CHAR_TABLE (char_table);
2226   CHECK_CHAR_COERCE_INT (character);
2227
2228   return get_char_table (XCHAR (character), XCHAR_TABLE (char_table));
2229 }
2230
2231 DEFUN ("get-range-char-table", Fget_range_char_table, 2, 3, 0, /*
2232 Find value for a range in CHAR-TABLE.
2233 If there is more than one value, return MULTI (defaults to nil).
2234 */
2235        (range, char_table, multi))
2236 {
2237   Lisp_Char_Table *ct;
2238   struct chartab_range rainj;
2239
2240   if (CHAR_OR_CHAR_INTP (range))
2241     return Fget_char_table (range, char_table);
2242   CHECK_CHAR_TABLE (char_table);
2243   ct = XCHAR_TABLE (char_table);
2244
2245   decode_char_table_range (range, &rainj);
2246   switch (rainj.type)
2247     {
2248     case CHARTAB_RANGE_ALL:
2249       {
2250 #ifdef UTF2000
2251         if (UINT8_BYTE_TABLE_P (ct->table))
2252           return multi;
2253         else if (UINT16_BYTE_TABLE_P (ct->table))
2254           return multi;
2255         else if (BYTE_TABLE_P (ct->table))
2256           return multi;
2257         else
2258           return ct->table;
2259 #else /* non UTF2000 */
2260         int i;
2261         Lisp_Object first = ct->ascii[0];
2262
2263         for (i = 1; i < NUM_ASCII_CHARS; i++)
2264           if (!EQ (first, ct->ascii[i]))
2265             return multi;
2266
2267 #ifdef MULE
2268         for (i = MIN_LEADING_BYTE; i < MIN_LEADING_BYTE + NUM_LEADING_BYTES;
2269              i++)
2270           {
2271             if (!CHARSETP (CHARSET_BY_LEADING_BYTE (i))
2272                 || i == LEADING_BYTE_ASCII
2273                 || i == LEADING_BYTE_CONTROL_1)
2274               continue;
2275             if (!EQ (first, ct->level1[i - MIN_LEADING_BYTE]))
2276               return multi;
2277           }
2278 #endif /* MULE */
2279
2280         return first;
2281 #endif /* non UTF2000 */
2282       }
2283
2284 #ifdef MULE
2285     case CHARTAB_RANGE_CHARSET:
2286 #ifdef UTF2000
2287       return multi;
2288 #else
2289       if (EQ (rainj.charset, Vcharset_ascii))
2290         {
2291           int i;
2292           Lisp_Object first = ct->ascii[0];
2293
2294           for (i = 1; i < 128; i++)
2295             if (!EQ (first, ct->ascii[i]))
2296               return multi;
2297           return first;
2298         }
2299
2300       if (EQ (rainj.charset, Vcharset_control_1))
2301         {
2302           int i;
2303           Lisp_Object first = ct->ascii[128];
2304
2305           for (i = 129; i < 160; i++)
2306             if (!EQ (first, ct->ascii[i]))
2307               return multi;
2308           return first;
2309         }
2310
2311       {
2312         Lisp_Object val = ct->level1[XCHARSET_LEADING_BYTE (rainj.charset) -
2313                                      MIN_LEADING_BYTE];
2314         if (CHAR_TABLE_ENTRYP (val))
2315           return multi;
2316         return val;
2317       }
2318 #endif
2319
2320     case CHARTAB_RANGE_ROW:
2321 #ifdef UTF2000
2322       return multi;
2323 #else
2324       {
2325         Lisp_Object val = ct->level1[XCHARSET_LEADING_BYTE (rainj.charset) -
2326                                      MIN_LEADING_BYTE];
2327         if (!CHAR_TABLE_ENTRYP (val))
2328           return val;
2329         val = XCHAR_TABLE_ENTRY (val)->level2[rainj.row - 32];
2330         if (CHAR_TABLE_ENTRYP (val))
2331           return multi;
2332         return val;
2333       }
2334 #endif /* not UTF2000 */
2335 #endif /* not MULE */
2336
2337     default:
2338       abort ();
2339     }
2340
2341   return Qnil; /* not reached */
2342 }
2343
2344 static int
2345 check_valid_char_table_value (Lisp_Object value, enum char_table_type type,
2346                               Error_behavior errb)
2347 {
2348   switch (type)
2349     {
2350     case CHAR_TABLE_TYPE_SYNTAX:
2351       if (!ERRB_EQ (errb, ERROR_ME))
2352         return INTP (value) || (CONSP (value) && INTP (XCAR (value))
2353                                 && CHAR_OR_CHAR_INTP (XCDR (value)));
2354       if (CONSP (value))
2355         {
2356           Lisp_Object cdr = XCDR (value);
2357           CHECK_INT (XCAR (value));
2358           CHECK_CHAR_COERCE_INT (cdr);
2359          }
2360       else
2361         CHECK_INT (value);
2362       break;
2363
2364 #ifdef MULE
2365     case CHAR_TABLE_TYPE_CATEGORY:
2366       if (!ERRB_EQ (errb, ERROR_ME))
2367         return CATEGORY_TABLE_VALUEP (value);
2368       CHECK_CATEGORY_TABLE_VALUE (value);
2369       break;
2370 #endif /* MULE */
2371
2372     case CHAR_TABLE_TYPE_GENERIC:
2373       return 1;
2374
2375     case CHAR_TABLE_TYPE_DISPLAY:
2376       /* #### fix this */
2377       maybe_signal_simple_error ("Display char tables not yet implemented",
2378                                  value, Qchar_table, errb);
2379       return 0;
2380
2381     case CHAR_TABLE_TYPE_CHAR:
2382       if (!ERRB_EQ (errb, ERROR_ME))
2383         return CHAR_OR_CHAR_INTP (value);
2384       CHECK_CHAR_COERCE_INT (value);
2385       break;
2386
2387     default:
2388       abort ();
2389     }
2390
2391   return 0; /* not reached */
2392 }
2393
2394 static Lisp_Object
2395 canonicalize_char_table_value (Lisp_Object value, enum char_table_type type)
2396 {
2397   switch (type)
2398     {
2399     case CHAR_TABLE_TYPE_SYNTAX:
2400       if (CONSP (value))
2401         {
2402           Lisp_Object car = XCAR (value);
2403           Lisp_Object cdr = XCDR (value);
2404           CHECK_CHAR_COERCE_INT (cdr);
2405           return Fcons (car, cdr);
2406         }
2407       break;
2408     case CHAR_TABLE_TYPE_CHAR:
2409       CHECK_CHAR_COERCE_INT (value);
2410       break;
2411     default:
2412       break;
2413     }
2414   return value;
2415 }
2416
2417 DEFUN ("valid-char-table-value-p", Fvalid_char_table_value_p, 2, 2, 0, /*
2418 Return non-nil if VALUE is a valid value for CHAR-TABLE-TYPE.
2419 */
2420        (value, char_table_type))
2421 {
2422   enum char_table_type type = symbol_to_char_table_type (char_table_type);
2423
2424   return check_valid_char_table_value (value, type, ERROR_ME_NOT) ? Qt : Qnil;
2425 }
2426
2427 DEFUN ("check-valid-char-table-value", Fcheck_valid_char_table_value, 2, 2, 0, /*
2428 Signal an error if VALUE is not a valid value for CHAR-TABLE-TYPE.
2429 */
2430        (value, char_table_type))
2431 {
2432   enum char_table_type type = symbol_to_char_table_type (char_table_type);
2433
2434   check_valid_char_table_value (value, type, ERROR_ME);
2435   return Qnil;
2436 }
2437
2438 #ifdef UTF2000
2439 Lisp_Char_Table* char_attribute_table_to_put;
2440 Lisp_Object Qput_char_table_map_function;
2441 Lisp_Object value_to_put;
2442
2443 DEFUN ("put-char-table-map-function",
2444        Fput_char_table_map_function, 2, 2, 0, /*
2445 For internal use.  Don't use it.
2446 */
2447        (c, value))
2448 {
2449   put_char_id_table_0 (char_attribute_table_to_put,
2450                        XCHAR (c), value_to_put);
2451   return Qnil;
2452 }
2453 #endif
2454
2455 /* Assign VAL to all characters in RANGE in char table CT. */
2456
2457 void
2458 put_char_table (Lisp_Char_Table *ct, struct chartab_range *range,
2459                 Lisp_Object val)
2460 {
2461   switch (range->type)
2462     {
2463     case CHARTAB_RANGE_ALL:
2464       fill_char_table (ct, val);
2465       return; /* avoid the duplicate call to update_syntax_table() below,
2466                  since fill_char_table() also did that. */
2467
2468 #ifdef UTF2000
2469     case CHARTAB_RANGE_DEFAULT:
2470       ct->default_value = val;
2471       return;
2472 #endif
2473
2474 #ifdef MULE
2475     case CHARTAB_RANGE_CHARSET:
2476 #ifdef UTF2000
2477       {
2478         Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (range->charset);
2479
2480         if ( CHAR_TABLEP (encoding_table) )
2481           {
2482             Lisp_Object mother = XCHARSET_MOTHER (range->charset);
2483
2484             char_attribute_table_to_put = ct;
2485             value_to_put = val;
2486             Fmap_char_attribute (Qput_char_table_map_function,
2487                                  XCHAR_TABLE_NAME (encoding_table),
2488                                  Qnil);
2489             if ( CHARSETP (mother) )
2490               {
2491                 struct chartab_range r;
2492
2493                 r.type = CHARTAB_RANGE_CHARSET;
2494                 r.charset = mother;
2495                 put_char_table (ct, &r, val);
2496               }
2497           }
2498 #if 0
2499         else
2500           {
2501             Emchar c;
2502
2503             for (c = 0; c < 1 << 24; c++)
2504               {
2505                 if ( charset_code_point (range->charset, c) >= 0 )
2506                   put_char_id_table_0 (ct, c, val);
2507               }
2508           }
2509 #endif
2510       }
2511 #else
2512       if (EQ (range->charset, Vcharset_ascii))
2513         {
2514           int i;
2515           for (i = 0; i < 128; i++)
2516             ct->ascii[i] = val;
2517         }
2518       else if (EQ (range->charset, Vcharset_control_1))
2519         {
2520           int i;
2521           for (i = 128; i < 160; i++)
2522             ct->ascii[i] = val;
2523         }
2524       else
2525         {
2526           int lb = XCHARSET_LEADING_BYTE (range->charset) - MIN_LEADING_BYTE;
2527           ct->level1[lb] = val;
2528         }
2529 #endif
2530       break;
2531
2532     case CHARTAB_RANGE_ROW:
2533 #ifdef UTF2000
2534       {
2535         int cell_min, cell_max, i;
2536
2537         i = XCHARSET_CELL_RANGE (range->charset);
2538         cell_min = i >> 8;
2539         cell_max = i & 0xFF;
2540         for (i = cell_min; i <= cell_max; i++)
2541           {
2542             Emchar ch
2543               = DECODE_CHAR (range->charset, (range->row << 8) | i, 0);
2544
2545             if ( charset_code_point (range->charset, ch, 0) >= 0 )
2546               put_char_id_table_0 (ct, ch, val);
2547           }
2548       }
2549 #else
2550       {
2551         Lisp_Char_Table_Entry *cte;
2552         int lb = XCHARSET_LEADING_BYTE (range->charset) - MIN_LEADING_BYTE;
2553         /* make sure that there is a separate entry for the row. */
2554         if (!CHAR_TABLE_ENTRYP (ct->level1[lb]))
2555           ct->level1[lb] = make_char_table_entry (ct->level1[lb]);
2556         cte = XCHAR_TABLE_ENTRY (ct->level1[lb]);
2557         cte->level2[range->row - 32] = val;
2558       }
2559 #endif /* not UTF2000 */
2560       break;
2561 #endif /* MULE */
2562
2563     case CHARTAB_RANGE_CHAR:
2564 #ifdef UTF2000
2565       put_char_id_table_0 (ct, range->ch, val);
2566       break;
2567 #elif defined(MULE)
2568       {
2569         Lisp_Object charset;
2570         int byte1, byte2;
2571
2572         BREAKUP_CHAR (range->ch, charset, byte1, byte2);
2573         if (EQ (charset, Vcharset_ascii))
2574           ct->ascii[byte1] = val;
2575         else if (EQ (charset, Vcharset_control_1))
2576           ct->ascii[byte1 + 128] = val;
2577         else
2578           {
2579             Lisp_Char_Table_Entry *cte;
2580             int lb = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE;
2581             /* make sure that there is a separate entry for the row. */
2582             if (!CHAR_TABLE_ENTRYP (ct->level1[lb]))
2583               ct->level1[lb] = make_char_table_entry (ct->level1[lb]);
2584             cte = XCHAR_TABLE_ENTRY (ct->level1[lb]);
2585             /* now CTE is a char table entry for the charset;
2586                each entry is for a single row (or character of
2587                a one-octet charset). */
2588             if (XCHARSET_DIMENSION (charset) == 1)
2589               cte->level2[byte1 - 32] = val;
2590             else
2591               {
2592                 /* assigning to one character in a two-octet charset. */
2593                 /* make sure that the charset row contains a separate
2594                    entry for each character. */
2595                 if (!CHAR_TABLE_ENTRYP (cte->level2[byte1 - 32]))
2596                   cte->level2[byte1 - 32] =
2597                     make_char_table_entry (cte->level2[byte1 - 32]);
2598                 cte = XCHAR_TABLE_ENTRY (cte->level2[byte1 - 32]);
2599                 cte->level2[byte2 - 32] = val;
2600               }
2601           }
2602       }
2603 #else /* not MULE */
2604       ct->ascii[(unsigned char) (range->ch)] = val;
2605       break;
2606 #endif /* not MULE */
2607     }
2608
2609 #ifndef UTF2000
2610   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
2611     update_syntax_table (ct);
2612 #endif
2613 }
2614
2615 DEFUN ("put-char-table", Fput_char_table, 3, 3, 0, /*
2616 Set the value for chars in RANGE to be VALUE in CHAR-TABLE.
2617
2618 RANGE specifies one or more characters to be affected and should be
2619 one of the following:
2620
2621 -- t (all characters are affected)
2622 -- A charset (only allowed when Mule support is present)
2623 -- A vector of two elements: a two-octet charset and a row number
2624    (only allowed when Mule support is present)
2625 -- A single character
2626
2627 VALUE must be a value appropriate for the type of CHAR-TABLE.
2628 See `valid-char-table-type-p'.
2629 */
2630        (range, value, char_table))
2631 {
2632   Lisp_Char_Table *ct;
2633   struct chartab_range rainj;
2634
2635   CHECK_CHAR_TABLE (char_table);
2636   ct = XCHAR_TABLE (char_table);
2637   check_valid_char_table_value (value, ct->type, ERROR_ME);
2638   decode_char_table_range (range, &rainj);
2639   value = canonicalize_char_table_value (value, ct->type);
2640   put_char_table (ct, &rainj, value);
2641   return Qnil;
2642 }
2643
2644 #ifndef UTF2000
2645 /* Map FN over the ASCII chars in CT. */
2646
2647 static int
2648 map_over_charset_ascii (Lisp_Char_Table *ct,
2649                         int (*fn) (struct chartab_range *range,
2650                                    Lisp_Object val, void *arg),
2651                         void *arg)
2652 {
2653   struct chartab_range rainj;
2654   int i, retval;
2655   int start = 0;
2656 #ifdef MULE
2657   int stop = 128;
2658 #else
2659   int stop = 256;
2660 #endif
2661
2662   rainj.type = CHARTAB_RANGE_CHAR;
2663
2664   for (i = start, retval = 0; i < stop && retval == 0; i++)
2665     {
2666       rainj.ch = (Emchar) i;
2667       retval = (fn) (&rainj, ct->ascii[i], arg);
2668     }
2669
2670   return retval;
2671 }
2672
2673 #ifdef MULE
2674
2675 /* Map FN over the Control-1 chars in CT. */
2676
2677 static int
2678 map_over_charset_control_1 (Lisp_Char_Table *ct,
2679                             int (*fn) (struct chartab_range *range,
2680                                        Lisp_Object val, void *arg),
2681                             void *arg)
2682 {
2683   struct chartab_range rainj;
2684   int i, retval;
2685   int start = 128;
2686   int stop  = start + 32;
2687
2688   rainj.type = CHARTAB_RANGE_CHAR;
2689
2690   for (i = start, retval = 0; i < stop && retval == 0; i++)
2691     {
2692       rainj.ch = (Emchar) (i);
2693       retval = (fn) (&rainj, ct->ascii[i], arg);
2694     }
2695
2696   return retval;
2697 }
2698
2699 /* Map FN over the row ROW of two-byte charset CHARSET.
2700    There must be a separate value for that row in the char table.
2701    CTE specifies the char table entry for CHARSET. */
2702
2703 static int
2704 map_over_charset_row (Lisp_Char_Table_Entry *cte,
2705                       Lisp_Object charset, int row,
2706                       int (*fn) (struct chartab_range *range,
2707                                  Lisp_Object val, void *arg),
2708                       void *arg)
2709 {
2710   Lisp_Object val = cte->level2[row - 32];
2711
2712   if (!CHAR_TABLE_ENTRYP (val))
2713     {
2714       struct chartab_range rainj;
2715
2716       rainj.type = CHARTAB_RANGE_ROW;
2717       rainj.charset = charset;
2718       rainj.row = row;
2719       return (fn) (&rainj, val, arg);
2720     }
2721   else
2722     {
2723       struct chartab_range rainj;
2724       int i, retval;
2725       int charset94_p = (XCHARSET_CHARS (charset) == 94);
2726       int start = charset94_p ?  33 :  32;
2727       int stop  = charset94_p ? 127 : 128;
2728
2729       cte = XCHAR_TABLE_ENTRY (val);
2730
2731       rainj.type = CHARTAB_RANGE_CHAR;
2732
2733       for (i = start, retval = 0; i < stop && retval == 0; i++)
2734         {
2735           rainj.ch = MAKE_CHAR (charset, row, i);
2736           retval = (fn) (&rainj, cte->level2[i - 32], arg);
2737         }
2738       return retval;
2739     }
2740 }
2741
2742
2743 static int
2744 map_over_other_charset (Lisp_Char_Table *ct, Charset_ID lb,
2745                         int (*fn) (struct chartab_range *range,
2746                                    Lisp_Object val, void *arg),
2747                         void *arg)
2748 {
2749   Lisp_Object val = ct->level1[lb - MIN_LEADING_BYTE];
2750   Lisp_Object charset = CHARSET_BY_LEADING_BYTE (lb);
2751
2752   if (!CHARSETP (charset)
2753       || lb == LEADING_BYTE_ASCII
2754       || lb == LEADING_BYTE_CONTROL_1)
2755     return 0;
2756
2757   if (!CHAR_TABLE_ENTRYP (val))
2758     {
2759       struct chartab_range rainj;
2760
2761       rainj.type = CHARTAB_RANGE_CHARSET;
2762       rainj.charset = charset;
2763       return (fn) (&rainj, val, arg);
2764     }
2765
2766   {
2767     Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (val);
2768     int charset94_p = (XCHARSET_CHARS (charset) == 94);
2769     int start = charset94_p ?  33 :  32;
2770     int stop  = charset94_p ? 127 : 128;
2771     int i, retval;
2772
2773     if (XCHARSET_DIMENSION (charset) == 1)
2774       {
2775         struct chartab_range rainj;
2776         rainj.type = CHARTAB_RANGE_CHAR;
2777
2778         for (i = start, retval = 0; i < stop && retval == 0; i++)
2779           {
2780             rainj.ch = MAKE_CHAR (charset, i, 0);
2781             retval = (fn) (&rainj, cte->level2[i - 32], arg);
2782           }
2783       }
2784     else
2785       {
2786         for (i = start, retval = 0; i < stop && retval == 0; i++)
2787           retval = map_over_charset_row (cte, charset, i, fn, arg);
2788       }
2789
2790     return retval;
2791   }
2792 }
2793
2794 #endif /* MULE */
2795 #endif /* not UTF2000 */
2796
2797 #ifdef UTF2000
2798 struct map_char_table_for_charset_arg
2799 {
2800   int (*fn) (struct chartab_range *range, Lisp_Object val, void *arg);
2801   Lisp_Char_Table *ct;
2802   void *arg;
2803 };
2804
2805 static int
2806 map_char_table_for_charset_fun (struct chartab_range *range,
2807                                 Lisp_Object val, void *arg)
2808 {
2809   struct map_char_table_for_charset_arg *closure =
2810     (struct map_char_table_for_charset_arg *) arg;
2811   Lisp_Object ret;
2812
2813   switch (range->type)
2814     {
2815     case CHARTAB_RANGE_ALL:
2816       break;
2817
2818     case CHARTAB_RANGE_DEFAULT:
2819       break;
2820
2821     case CHARTAB_RANGE_CHARSET:
2822       break;
2823
2824     case CHARTAB_RANGE_ROW:
2825       break;
2826
2827     case CHARTAB_RANGE_CHAR:
2828       ret = get_char_table (range->ch, closure->ct);
2829       if (!UNBOUNDP (ret))
2830         return (closure->fn) (range, ret, closure->arg);
2831       break;
2832
2833     default:
2834       abort ();
2835     }
2836
2837   return 0;
2838 }
2839
2840 #endif
2841
2842 /* Map FN (with client data ARG) over range RANGE in char table CT.
2843    Mapping stops the first time FN returns non-zero, and that value
2844    becomes the return value of map_char_table(). */
2845
2846 int
2847 map_char_table (Lisp_Char_Table *ct,
2848                 struct chartab_range *range,
2849                 int (*fn) (struct chartab_range *range,
2850                            Lisp_Object val, void *arg),
2851                 void *arg)
2852 {
2853   switch (range->type)
2854     {
2855     case CHARTAB_RANGE_ALL:
2856 #ifdef UTF2000
2857       if (!UNBOUNDP (ct->default_value))
2858         {
2859           struct chartab_range rainj;
2860           int retval;
2861
2862           rainj.type = CHARTAB_RANGE_DEFAULT;
2863           retval = (fn) (&rainj, ct->default_value, arg);
2864           if (retval != 0)
2865             return retval;
2866         }
2867       if (UINT8_BYTE_TABLE_P (ct->table))
2868         return map_over_uint8_byte_table (XUINT8_BYTE_TABLE(ct->table), ct,
2869                                           0, 3, fn, arg);
2870       else if (UINT16_BYTE_TABLE_P (ct->table))
2871         return map_over_uint16_byte_table (XUINT16_BYTE_TABLE(ct->table), ct,
2872                                            0, 3, fn, arg);
2873       else if (BYTE_TABLE_P (ct->table))
2874         return map_over_byte_table (XBYTE_TABLE(ct->table), ct,
2875                                     0, 3, fn, arg);
2876       else if (EQ (ct->table, Qunloaded))
2877         {
2878 #if 0
2879           struct chartab_range rainj;
2880           int unit = 1 << 30;
2881           Emchar c = 0;
2882           Emchar c1 = c + unit;
2883           int retval;
2884
2885           rainj.type = CHARTAB_RANGE_CHAR;
2886
2887           for (retval = 0; c < c1 && retval == 0; c++)
2888             {
2889               Lisp_Object ret = get_char_id_table (ct, c);
2890
2891               if (!UNBOUNDP (ret))
2892                 {
2893                   rainj.ch = c;
2894                   retval = (fn) (&rainj, ct->table, arg);
2895                 }
2896             }
2897           return retval;
2898 #else
2899           ct->table = Qunbound;
2900 #endif
2901         }
2902       else if (!UNBOUNDP (ct->table))
2903         return (fn) (range, ct->table, arg);
2904       return 0;
2905 #else
2906       {
2907         int retval;
2908
2909         retval = map_over_charset_ascii (ct, fn, arg);
2910         if (retval)
2911           return retval;
2912 #ifdef MULE
2913         retval = map_over_charset_control_1 (ct, fn, arg);
2914         if (retval)
2915           return retval;
2916         {
2917           Charset_ID i;
2918           Charset_ID start = MIN_LEADING_BYTE;
2919           Charset_ID stop  = start + NUM_LEADING_BYTES;
2920
2921           for (i = start, retval = 0; i < stop && retval == 0; i++)
2922             {
2923               retval = map_over_other_charset (ct, i, fn, arg);
2924             }
2925         }
2926 #endif /* MULE */
2927         return retval;
2928       }
2929 #endif
2930
2931 #ifdef UTF2000
2932     case CHARTAB_RANGE_DEFAULT:
2933       if (!UNBOUNDP (ct->default_value))
2934         return (fn) (range, ct->default_value, arg);
2935       return 0;
2936 #endif
2937
2938 #ifdef MULE
2939     case CHARTAB_RANGE_CHARSET:
2940 #ifdef UTF2000
2941       {
2942         Lisp_Object encoding_table
2943           = XCHARSET_ENCODING_TABLE (range->charset);
2944
2945         if (!NILP (encoding_table))
2946           {
2947             struct chartab_range rainj;
2948             struct map_char_table_for_charset_arg mcarg;
2949
2950 #ifdef HAVE_CHISE
2951             if (XCHAR_TABLE_UNLOADED(encoding_table))
2952               Fload_char_attribute_table (XCHAR_TABLE_NAME (encoding_table));
2953 #endif
2954             mcarg.fn = fn;
2955             mcarg.ct = ct;
2956             mcarg.arg = arg;
2957             rainj.type = CHARTAB_RANGE_ALL;
2958             return map_char_table (XCHAR_TABLE(encoding_table),
2959                                    &rainj,
2960                                    &map_char_table_for_charset_fun,
2961                                    &mcarg);
2962           }
2963       }
2964       return 0;
2965 #else
2966       return map_over_other_charset (ct,
2967                                      XCHARSET_LEADING_BYTE (range->charset),
2968                                      fn, arg);
2969 #endif
2970
2971     case CHARTAB_RANGE_ROW:
2972 #ifdef UTF2000
2973       {
2974         int cell_min, cell_max, i;
2975         int retval;
2976         struct chartab_range rainj;
2977
2978         i = XCHARSET_CELL_RANGE (range->charset);
2979         cell_min = i >> 8;
2980         cell_max = i & 0xFF;
2981         rainj.type = CHARTAB_RANGE_CHAR;
2982         for (retval =0, i = cell_min; i <= cell_max && retval == 0; i++)
2983           {
2984             Emchar ch
2985               = DECODE_CHAR (range->charset, (range->row << 8) | i, 0);
2986
2987             if ( charset_code_point (range->charset, ch, 0) >= 0 )
2988               {
2989                 Lisp_Object val
2990                   = get_byte_table (get_byte_table
2991                                     (get_byte_table
2992                                      (get_byte_table
2993                                       (ct->table,
2994                                        (unsigned char)(ch >> 24)),
2995                                       (unsigned char) (ch >> 16)),
2996                                      (unsigned char)  (ch >> 8)),
2997                                     (unsigned char)    ch);
2998
2999                 if (UNBOUNDP (val))
3000                   val = ct->default_value;
3001                 rainj.ch = ch;
3002                 retval = (fn) (&rainj, val, arg);
3003               }
3004           }
3005         return retval;
3006       }
3007 #else
3008       {
3009         Lisp_Object val = ct->level1[XCHARSET_LEADING_BYTE (range->charset)
3010                                     - MIN_LEADING_BYTE];
3011         if (!CHAR_TABLE_ENTRYP (val))
3012           {
3013             struct chartab_range rainj;
3014
3015             rainj.type = CHARTAB_RANGE_ROW;
3016             rainj.charset = range->charset;
3017             rainj.row = range->row;
3018             return (fn) (&rainj, val, arg);
3019           }
3020         else
3021           return map_over_charset_row (XCHAR_TABLE_ENTRY (val),
3022                                        range->charset, range->row,
3023                                        fn, arg);
3024       }
3025 #endif /* not UTF2000 */
3026 #endif /* MULE */
3027
3028     case CHARTAB_RANGE_CHAR:
3029       {
3030         Emchar ch = range->ch;
3031         Lisp_Object val = CHAR_TABLE_VALUE_UNSAFE (ct, ch);
3032
3033         if (!UNBOUNDP (val))
3034           {
3035             struct chartab_range rainj;
3036
3037             rainj.type = CHARTAB_RANGE_CHAR;
3038             rainj.ch = ch;
3039             return (fn) (&rainj, val, arg);
3040           }
3041         return 0;
3042       }
3043
3044     default:
3045       abort ();
3046     }
3047
3048   return 0;
3049 }
3050
3051 struct slow_map_char_table_arg
3052 {
3053   Lisp_Object function;
3054   Lisp_Object retval;
3055 };
3056
3057 static int
3058 slow_map_char_table_fun (struct chartab_range *range,
3059                          Lisp_Object val, void *arg)
3060 {
3061   Lisp_Object ranjarg = Qnil;
3062   struct slow_map_char_table_arg *closure =
3063     (struct slow_map_char_table_arg *) arg;
3064
3065   switch (range->type)
3066     {
3067     case CHARTAB_RANGE_ALL:
3068       ranjarg = Qt;
3069       break;
3070
3071 #ifdef UTF2000
3072     case CHARTAB_RANGE_DEFAULT:
3073       ranjarg = Qnil;
3074       break;
3075 #endif
3076
3077 #ifdef MULE
3078     case CHARTAB_RANGE_CHARSET:
3079       ranjarg = XCHARSET_NAME (range->charset);
3080       break;
3081
3082     case CHARTAB_RANGE_ROW:
3083       ranjarg = vector2 (XCHARSET_NAME (range->charset),
3084                          make_int (range->row));
3085       break;
3086 #endif /* MULE */
3087     case CHARTAB_RANGE_CHAR:
3088       ranjarg = make_char (range->ch);
3089       break;
3090     default:
3091       abort ();
3092     }
3093
3094   closure->retval = call2 (closure->function, ranjarg, val);
3095   return !NILP (closure->retval);
3096 }
3097
3098 DEFUN ("map-char-table", Fmap_char_table, 2, 3, 0, /*
3099 Map FUNCTION over entries in CHAR-TABLE, calling it with two args,
3100 each key and value in the table.
3101
3102 RANGE specifies a subrange to map over and is in the same format as
3103 the RANGE argument to `put-range-table'.  If omitted or t, it defaults to
3104 the entire table.
3105 */
3106        (function, char_table, range))
3107 {
3108   Lisp_Char_Table *ct;
3109   struct slow_map_char_table_arg slarg;
3110   struct gcpro gcpro1, gcpro2;
3111   struct chartab_range rainj;
3112
3113   CHECK_CHAR_TABLE (char_table);
3114   ct = XCHAR_TABLE (char_table);
3115   if (NILP (range))
3116     range = Qt;
3117   decode_char_table_range (range, &rainj);
3118   slarg.function = function;
3119   slarg.retval = Qnil;
3120   GCPRO2 (slarg.function, slarg.retval);
3121   map_char_table (ct, &rainj, slow_map_char_table_fun, &slarg);
3122   UNGCPRO;
3123
3124   return slarg.retval;
3125 }
3126
3127 \f
3128 /************************************************************************/
3129 /*                         Character Attributes                         */
3130 /************************************************************************/
3131
3132 #ifdef UTF2000
3133
3134 Lisp_Object Vchar_attribute_hash_table;
3135
3136 /* We store the char-attributes in hash tables with the names as the
3137    key and the actual char-id-table object as the value.  Occasionally
3138    we need to use them in a list format.  These routines provide us
3139    with that. */
3140 struct char_attribute_list_closure
3141 {
3142   Lisp_Object *char_attribute_list;
3143 };
3144
3145 static int
3146 add_char_attribute_to_list_mapper (Lisp_Object key, Lisp_Object value,
3147                                    void *char_attribute_list_closure)
3148 {
3149   /* This function can GC */
3150   struct char_attribute_list_closure *calcl
3151     = (struct char_attribute_list_closure*) char_attribute_list_closure;
3152   Lisp_Object *char_attribute_list = calcl->char_attribute_list;
3153
3154   *char_attribute_list = Fcons (key, *char_attribute_list);
3155   return 0;
3156 }
3157
3158 #ifdef HAVE_LIBCHISE
3159 static int
3160 char_attribute_list_reset_map_func (CHISE_DS *ds, unsigned char *name)
3161 {
3162   Fmount_char_attribute_table (intern (name));
3163   return 0;
3164 }
3165
3166 DEFUN ("char-attribute-list", Fchar_attribute_list, 0, 1, 0, /*
3167 Return the list of all existing character attributes except coded-charsets.
3168 */
3169        (rehash))
3170 #else
3171 DEFUN ("char-attribute-list", Fchar_attribute_list, 0, 0, 0, /*
3172 Return the list of all existing character attributes except coded-charsets.
3173 */
3174        ())
3175 #endif
3176 {
3177   Lisp_Object char_attribute_list = Qnil;
3178   struct gcpro gcpro1;
3179   struct char_attribute_list_closure char_attribute_list_closure;
3180   
3181 #ifdef HAVE_LIBCHISE
3182   if (!NILP (rehash))
3183     {
3184       open_chise_data_source_maybe ();
3185       chise_ds_foreach_char_feature_name
3186         (default_chise_data_source, &char_attribute_list_reset_map_func);
3187     }
3188 #endif
3189   GCPRO1 (char_attribute_list);
3190   char_attribute_list_closure.char_attribute_list = &char_attribute_list;
3191   elisp_maphash (add_char_attribute_to_list_mapper,
3192                  Vchar_attribute_hash_table,
3193                  &char_attribute_list_closure);
3194   UNGCPRO;
3195   return char_attribute_list;
3196 }
3197
3198 DEFUN ("find-char-attribute-table", Ffind_char_attribute_table, 1, 1, 0, /*
3199 Return char-id-table corresponding to ATTRIBUTE.
3200 */
3201        (attribute))
3202 {
3203   return Fgethash (attribute, Vchar_attribute_hash_table, Qnil);
3204 }
3205
3206
3207 /* We store the char-id-tables in hash tables with the attributes as
3208    the key and the actual char-id-table object as the value.  Each
3209    char-id-table stores values of an attribute corresponding with
3210    characters.  Occasionally we need to get attributes of a character
3211    in a association-list format.  These routines provide us with
3212    that. */
3213 struct char_attribute_alist_closure
3214 {
3215   Emchar char_id;
3216   Lisp_Object *char_attribute_alist;
3217 };
3218
3219 static int
3220 add_char_attribute_alist_mapper (Lisp_Object key, Lisp_Object value,
3221                                  void *char_attribute_alist_closure)
3222 {
3223   /* This function can GC */
3224   struct char_attribute_alist_closure *caacl =
3225     (struct char_attribute_alist_closure*) char_attribute_alist_closure;
3226   Lisp_Object ret
3227     = get_char_id_table (XCHAR_TABLE(value), caacl->char_id);
3228   if (!UNBOUNDP (ret))
3229     {
3230       Lisp_Object *char_attribute_alist = caacl->char_attribute_alist;
3231       *char_attribute_alist
3232         = Fcons (Fcons (key, ret), *char_attribute_alist);
3233     }
3234   return 0;
3235 }
3236
3237 DEFUN ("char-attribute-alist", Fchar_attribute_alist, 1, 1, 0, /*
3238 Return the alist of attributes of CHARACTER.
3239 */
3240        (character))
3241 {
3242   struct gcpro gcpro1;
3243   struct char_attribute_alist_closure char_attribute_alist_closure;
3244   Lisp_Object alist = Qnil;
3245
3246   CHECK_CHAR (character);
3247
3248   GCPRO1 (alist);
3249   char_attribute_alist_closure.char_id = XCHAR (character);
3250   char_attribute_alist_closure.char_attribute_alist = &alist;
3251   elisp_maphash (add_char_attribute_alist_mapper,
3252                  Vchar_attribute_hash_table,
3253                  &char_attribute_alist_closure);
3254   UNGCPRO;
3255
3256   return alist;
3257 }
3258
3259 DEFUN ("get-char-attribute", Fget_char_attribute, 2, 3, 0, /*
3260 Return the value of CHARACTER's ATTRIBUTE.
3261 Return DEFAULT-VALUE if the value is not exist.
3262 */
3263        (character, attribute, default_value))
3264 {
3265   Lisp_Object table;
3266
3267   CHECK_CHAR (character);
3268
3269   if (CHARSETP (attribute))
3270     attribute = XCHARSET_NAME (attribute);
3271
3272   table = Fgethash (attribute, Vchar_attribute_hash_table,
3273                     Qunbound);
3274   if (!UNBOUNDP (table))
3275     {
3276       Lisp_Object ret = get_char_id_table (XCHAR_TABLE(table),
3277                                            XCHAR (character));
3278       if (!UNBOUNDP (ret))
3279         return ret;
3280     }
3281   return default_value;
3282 }
3283
3284 static Lisp_Object
3285 find_char_feature_in_family (Lisp_Object character,
3286                              Lisp_Object con_feature,
3287                              Lisp_Object feature,
3288                              Lisp_Object feature_rel_max)
3289 {
3290   Lisp_Object ancestors
3291     = Fget_char_attribute (character, con_feature, Qnil);
3292
3293   while (!NILP (ancestors))
3294     {
3295       Lisp_Object ancestor = XCAR (ancestors);
3296       Lisp_Object ret;
3297
3298       if (EQ (ancestor, character))
3299         return Qunbound;
3300
3301       ret = Fchar_feature (ancestor, feature, Qunbound,
3302                            Qnil, make_int (0));
3303       if (!UNBOUNDP (ret))
3304         return ret;
3305
3306       ancestors = XCDR (ancestors);
3307
3308       ret = Fget_char_attribute (ancestor, Q_subsumptive_from, Qnil);
3309       if (!NILP (ret))
3310         ancestors = nconc2 (Fcopy_sequence (ancestors), ret);
3311
3312       ret = Fget_char_attribute (ancestor, Q_denotational_from, Qnil);
3313       if (!NILP (ret))
3314         ancestors = nconc2 (Fcopy_sequence (ancestors), ret);
3315     }
3316   return Qunbound;
3317 }
3318
3319 DEFUN ("char-feature", Fchar_feature, 2, 5, 0, /*
3320 Return the value of CHARACTER's FEATURE.
3321 Return DEFAULT-VALUE if the value is not exist.
3322 */
3323        (character, attribute, default_value,
3324         feature_rel_max, char_rel_max))
3325 {
3326   Lisp_Object ret
3327     = Fget_char_attribute (character, attribute, Qunbound);
3328
3329   if (!UNBOUNDP (ret))
3330     return ret;
3331
3332   if (NILP (feature_rel_max)
3333       || (INTP (feature_rel_max) &&
3334           XINT (feature_rel_max) > 0))
3335     {
3336       Lisp_String* name = symbol_name (XSYMBOL (attribute));
3337       Bufbyte *name_str = string_data (name);
3338
3339       if (name_str[0] == '=' && name_str[1] == '>')
3340         {
3341           Bytecount length = string_length (name) - 1;
3342           Lisp_Object map_to = make_uninit_string (length);
3343
3344           memcpy (XSTRING_DATA (map_to) + 1, name_str + 2, length - 1);
3345           XSTRING_DATA(map_to)[0] = '=';
3346           ret = Fchar_feature (character, Fintern (map_to, Qnil),
3347                                Qunbound,
3348                                NILP (feature_rel_max)
3349                                ? feature_rel_max
3350                                : make_int (XINT (feature_rel_max) - 1),
3351                                char_rel_max);
3352           if (!UNBOUNDP (ret))
3353             return ret;
3354         }
3355     }
3356
3357   if ( !(EQ (attribute, Q_identical)) &&
3358        !(EQ (attribute, Q_subsumptive_from)) &&
3359        !(EQ (attribute, Q_denotational_from)) &&
3360        ( (NILP (char_rel_max)
3361           || (INTP (char_rel_max) &&
3362               XINT (char_rel_max) > 0)) ) )
3363     {
3364       Lisp_String* name = symbol_name (XSYMBOL (attribute));
3365       Bufbyte *name_str = string_data (name);
3366
3367       if ( (name_str[0] != '=') || (name_str[1] == '>') )
3368         {
3369           ret = find_char_feature_in_family (character, Q_identical,
3370                                              attribute, feature_rel_max);
3371           if (!UNBOUNDP (ret))
3372             return ret;
3373
3374           ret = find_char_feature_in_family (character, Q_subsumptive_from,
3375                                              attribute, feature_rel_max);
3376           if (!UNBOUNDP (ret))
3377             return ret;
3378
3379           ret = find_char_feature_in_family (character, Q_denotational_from,
3380                                              attribute, feature_rel_max);
3381           if (!UNBOUNDP (ret))
3382             return ret;
3383         }
3384     }
3385   return default_value;
3386 }
3387
3388 void put_char_composition (Lisp_Object character, Lisp_Object value);
3389 void
3390 put_char_composition (Lisp_Object character, Lisp_Object value)
3391 {
3392   if (!CONSP (value))
3393     signal_simple_error ("Invalid value for ->decomposition",
3394                          value);
3395
3396   if (CONSP (Fcdr (value)))
3397     {
3398       if (NILP (Fcdr (Fcdr (value))))
3399         {
3400           Lisp_Object base = Fcar (value);
3401           Lisp_Object modifier = Fcar (Fcdr (value));
3402
3403           if (INTP (base))
3404             {
3405               base = make_char (XINT (base));
3406               Fsetcar (value, base);
3407             }
3408           if (INTP (modifier))
3409             {
3410               modifier = make_char (XINT (modifier));
3411               Fsetcar (Fcdr (value), modifier);
3412             }
3413           if (CHARP (base))
3414             {
3415               Lisp_Object alist
3416                 = Fchar_feature (base, Qcomposition, Qnil,
3417                                  Qnil, Qnil);
3418               Lisp_Object ret = Fassq (modifier, alist);
3419
3420               if (NILP (ret))
3421                 Fput_char_attribute (base, Qcomposition,
3422                                      Fcons (Fcons (modifier, character),
3423                                             alist));
3424               else
3425                 Fsetcdr (ret, character);
3426             }
3427         }
3428     }
3429   else
3430     {
3431       Lisp_Object v = Fcar (value);
3432
3433       if (INTP (v))
3434         {
3435           Emchar c = XINT (v);
3436           Lisp_Object ret
3437             = Fchar_feature (make_char (c), Q_ucs_unified, Qnil,
3438                              Qnil, Qnil);
3439
3440           if (!CONSP (ret))
3441             {
3442               Fput_char_attribute (make_char (c), Q_ucs_unified,
3443                                    Fcons (character, Qnil));
3444             }
3445           else if (NILP (Fmemq (character, ret)))
3446             {
3447               Fput_char_attribute (make_char (c), Q_ucs_unified,
3448                                    Fcons (character, ret));
3449             }
3450         }
3451     }
3452 }
3453
3454 static Lisp_Object
3455 put_char_attribute (Lisp_Object character, Lisp_Object attribute,
3456                     Lisp_Object value)
3457 {
3458   Lisp_Object table = Fgethash (attribute,
3459                                 Vchar_attribute_hash_table,
3460                                 Qnil);
3461
3462   if (NILP (table))
3463     {
3464       table = make_char_id_table (Qunbound);
3465       Fputhash (attribute, table, Vchar_attribute_hash_table);
3466 #ifdef HAVE_CHISE
3467       XCHAR_TABLE_NAME (table) = attribute;
3468 #endif
3469     }
3470   put_char_id_table (XCHAR_TABLE(table), character, value);
3471   return value;
3472 }
3473
3474 DEFUN ("put-char-attribute", Fput_char_attribute, 3, 3, 0, /*
3475 Store CHARACTER's ATTRIBUTE with VALUE.
3476 */
3477        (character, attribute, value))
3478 {
3479   Lisp_Object ccs = Ffind_charset (attribute);
3480
3481   CHECK_CHAR (character);
3482
3483   if (!NILP (ccs))
3484     {
3485       value = put_char_ccs_code_point (character, ccs, value);
3486       attribute = XCHARSET_NAME (ccs);
3487     }
3488   else if (EQ (attribute, Q_decomposition))
3489     put_char_composition (character, value);
3490   else if (EQ (attribute, Qto_ucs))
3491     {
3492       Lisp_Object ret;
3493       Emchar c;
3494
3495       if (!INTP (value))
3496         signal_simple_error ("Invalid value for =>ucs", value);
3497
3498       c = XINT (value);
3499
3500       ret = Fchar_feature (make_char (c), Q_ucs_unified, Qnil,
3501                            Qnil, Qnil);
3502       if (!CONSP (ret))
3503         put_char_attribute (make_char (c), Q_ucs_unified,
3504                             list1 (character));
3505       else if (NILP (Fmemq (character, ret)))
3506         Fput_char_attribute (make_char (c), Q_ucs_unified,
3507                              Fcons (character, ret));
3508     }
3509   else if ( EQ (attribute, Q_subsumptive) ||
3510             EQ (attribute, Q_subsumptive_from) ||
3511             EQ (attribute, Q_denotational) ||
3512             EQ (attribute, Q_denotational_from) ||
3513             EQ (attribute, Q_identical) ||
3514             EQ (attribute, Q_identical_from) ||
3515             EQ (attribute, Q_component) ||
3516             EQ (attribute, Q_component_of) ||
3517             EQ (attribute, Q_same) ||
3518             EQ (attribute, Q_same_of) ||
3519             !NILP (Fstring_match (build_string ("^<-simplified[^*]*$"),
3520                                   Fsymbol_name (attribute),
3521                                   Qnil, Qnil)) )
3522     {
3523       Lisp_Object rest = value;
3524       Lisp_Object ret;
3525       Lisp_Object rev_feature = Qnil;
3526       struct gcpro gcpro1;
3527       GCPRO1 (rev_feature);
3528
3529       if (EQ (attribute, Q_identical))
3530         rev_feature = Q_identical_from;
3531       else if (EQ (attribute, Q_identical_from))
3532         rev_feature = Q_identical;
3533       else if (EQ (attribute, Q_subsumptive))
3534         rev_feature = Q_subsumptive_from;
3535       else if (EQ (attribute, Q_subsumptive_from))
3536         rev_feature = Q_subsumptive;
3537       else if (EQ (attribute, Q_denotational))
3538         rev_feature = Q_denotational_from;
3539       else if (EQ (attribute, Q_denotational_from))
3540         rev_feature = Q_denotational;
3541       else if (EQ (attribute, Q_component))
3542         rev_feature = Q_component_of;
3543       else if (EQ (attribute, Q_component_of))
3544         rev_feature = Q_component;
3545       else if (EQ (attribute, Q_same))
3546         rev_feature = Q_same_of;
3547       else if (EQ (attribute, Q_same_of))
3548         rev_feature = Q_same;
3549       else
3550         {
3551           Lisp_String* name = symbol_name (XSYMBOL (attribute));
3552           Bufbyte *name_str = string_data (name);
3553
3554           if (name_str[0] == '<' && name_str[1] == '-')
3555             {
3556               Bytecount length = string_length (name);
3557               Bufbyte *rev_name_str = alloca (length + 1);
3558
3559               memcpy (rev_name_str + 2, name_str + 2, length - 2);
3560               rev_name_str[0] = '-';
3561               rev_name_str[1] = '>';
3562               rev_name_str[length] = 0;
3563               rev_feature = intern (rev_name_str);
3564             }
3565         }
3566
3567       while (CONSP (rest))
3568         {
3569           ret = XCAR (rest);
3570
3571           if (CONSP (ret))
3572             ret = Fdefine_char (ret);
3573           
3574           if ( !NILP (ret) && !EQ (ret, character) )
3575             {
3576               Lisp_Object ffv;
3577
3578               ffv = Fget_char_attribute (ret, rev_feature, Qnil);
3579               if (!CONSP (ffv))
3580                 put_char_attribute (ret, rev_feature, list1 (character));
3581               else if (NILP (Fmemq (character, ffv)))
3582                 put_char_attribute (ret, rev_feature,
3583                                     Fcons (character, ffv));
3584               Fsetcar (rest, ret);
3585             }
3586           rest = XCDR (rest);
3587         }
3588       UNGCPRO;
3589     }
3590 #if 1
3591   else if (EQ (attribute, Qideographic_structure))
3592     value = Fcopy_sequence (Fchar_refs_simplify_char_specs (value));
3593 #endif
3594   return put_char_attribute (character, attribute, value);
3595 }
3596   
3597 DEFUN ("remove-char-attribute", Fremove_char_attribute, 2, 2, 0, /*
3598 Remove CHARACTER's ATTRIBUTE.
3599 */
3600        (character, attribute))
3601 {
3602   Lisp_Object ccs;
3603
3604   CHECK_CHAR (character);
3605   ccs = Ffind_charset (attribute);
3606   if (!NILP (ccs))
3607     {
3608       return remove_char_ccs (character, ccs);
3609     }
3610   else
3611     {
3612       Lisp_Object table = Fgethash (attribute,
3613                                     Vchar_attribute_hash_table,
3614                                     Qunbound);
3615       if (!UNBOUNDP (table))
3616         {
3617           put_char_id_table (XCHAR_TABLE(table), character, Qunbound);
3618           return Qt;
3619         }
3620     }
3621   return Qnil;
3622 }
3623
3624 #ifdef HAVE_CHISE
3625
3626 int char_table_open_db_maybe (Lisp_Char_Table* cit);
3627 void char_table_close_db_maybe (Lisp_Char_Table* cit);
3628 Lisp_Object char_table_get_db (Lisp_Char_Table* cit, Emchar ch);
3629
3630 #ifdef HAVE_LIBCHISE
3631 int
3632 open_chise_data_source_maybe ()
3633 {
3634   if (default_chise_data_source == NULL)
3635     {
3636       Lisp_Object db_dir = Vexec_directory;
3637       int modemask = 0755;              /* rwxr-xr-x */
3638
3639       if (NILP (db_dir))
3640         db_dir = build_string ("../lib-src");
3641       db_dir = Fexpand_file_name (build_string ("chise-db"), db_dir);
3642
3643       default_chise_data_source
3644         = CHISE_DS_open (CHISE_DS_Berkeley_DB, XSTRING_DATA (db_dir),
3645                          0 /* DB_HASH */, modemask);
3646       if (default_chise_data_source == NULL)
3647         return -1;
3648     }
3649   return 0;
3650 }
3651 #endif /* HAVE_LIBCHISE */
3652
3653 DEFUN ("close-char-data-source", Fclose_char_data_source, 0, 0, 0, /*
3654 Close data-source of CHISE.
3655 */
3656        ())
3657 {
3658 #ifdef HAVE_LIBCHISE
3659   int status = CHISE_DS_close (default_chise_data_source);
3660
3661   default_chise_data_source = NULL;
3662   if (status)
3663     return Qt;
3664 #endif /* HAVE_LIBCHISE */
3665   return Qnil;
3666 }
3667
3668 int
3669 char_table_open_db_maybe (Lisp_Char_Table* cit)
3670 {
3671   Lisp_Object attribute = CHAR_TABLE_NAME (cit);
3672
3673   if (!NILP (attribute))
3674     {
3675 #ifdef HAVE_LIBCHISE
3676       if ( open_chise_data_source_maybe () )
3677         return -1;
3678 #else /* HAVE_LIBCHISE */
3679       if (NILP (Fdatabase_live_p (cit->db)))
3680         {
3681           Lisp_Object db_file
3682             = char_attribute_system_db_file (Qsystem_char_id, attribute, 0);
3683
3684           cit->db = Fopen_database (db_file, Qnil, Qnil,
3685                                     build_string ("r"), Qnil);
3686           if (NILP (cit->db))
3687             return -1;
3688         }
3689 #endif /* not HAVE_LIBCHISE */
3690       return 0;
3691     }
3692   else
3693     return -1;
3694 }
3695
3696 void
3697 char_table_close_db_maybe (Lisp_Char_Table* cit)
3698 {
3699 #ifndef HAVE_LIBCHISE
3700   if (!NILP (cit->db))
3701     {
3702       if (!NILP (Fdatabase_live_p (cit->db)))
3703         Fclose_database (cit->db);
3704       cit->db = Qnil;
3705     }
3706 #endif /* not HAVE_LIBCHISE */
3707 }
3708
3709 Lisp_Object
3710 char_table_get_db (Lisp_Char_Table* cit, Emchar ch)
3711 {
3712   Lisp_Object val;
3713 #ifdef HAVE_LIBCHISE
3714   CHISE_Value value;
3715   int status
3716     = chise_ds_load_char_feature_value (default_chise_data_source, ch,
3717                                         XSTRING_DATA(Fsymbol_name
3718                                                      (cit->name)),
3719                                         &value);
3720
3721   if (!status)
3722     {
3723       val = Fread (make_string (chise_value_data (&value),
3724                                 chise_value_size (&value) ));
3725     }
3726   else
3727     val = Qunbound;
3728 #else /* HAVE_LIBCHISE */
3729   val = Fget_database (Fprin1_to_string (make_char (ch), Qnil),
3730                        cit->db, Qunbound);
3731   if (!UNBOUNDP (val))
3732     val = Fread (val);
3733   else
3734     val = Qunbound;
3735 #endif /* not HAVE_LIBCHISE */
3736   return val;
3737 }
3738
3739 #ifndef HAVE_LIBCHISE
3740 Lisp_Object
3741 char_attribute_system_db_file (Lisp_Object key_type, Lisp_Object attribute,
3742                                int writing_mode)
3743 {
3744   Lisp_Object db_dir = Vexec_directory;
3745
3746   if (NILP (db_dir))
3747     db_dir = build_string ("../lib-src");
3748
3749   db_dir = Fexpand_file_name (build_string ("chise-db"), db_dir);
3750   if (writing_mode && NILP (Ffile_exists_p (db_dir)))
3751     Fmake_directory_internal (db_dir);
3752
3753   db_dir = Fexpand_file_name (Fsymbol_name (key_type), db_dir);
3754   if (writing_mode && NILP (Ffile_exists_p (db_dir)))
3755     Fmake_directory_internal (db_dir);
3756
3757   {
3758     Lisp_Object attribute_name = Fsymbol_name (attribute);
3759     Lisp_Object dest = Qnil, ret;
3760     int base = 0;
3761     struct gcpro gcpro1, gcpro2;
3762     int len = XSTRING_CHAR_LENGTH (attribute_name);
3763     int i;
3764
3765     GCPRO2 (dest, ret);
3766     for (i = 0; i < len; i++)
3767       {
3768         Emchar c = string_char (XSTRING (attribute_name), i);
3769
3770         if ( (c == '/') || (c == '%') )
3771           {
3772             char str[4];
3773
3774             sprintf (str, "%%%02X", c);
3775             dest = concat3 (dest,
3776                             Fsubstring (attribute_name,
3777                                         make_int (base), make_int (i)),
3778                             build_string (str));
3779             base = i + 1;
3780           }
3781       }
3782     ret = Fsubstring (attribute_name, make_int (base), make_int (len));
3783     dest = concat2 (dest, ret);
3784     UNGCPRO;
3785     return Fexpand_file_name (dest, db_dir);
3786   }
3787 }
3788 #endif /* not HAVE_LIBCHISE */
3789
3790 DEFUN ("save-char-attribute-table", Fsave_char_attribute_table, 1, 1, 0, /*
3791 Save values of ATTRIBUTE into database file.
3792 */
3793        (attribute))
3794 {
3795   Lisp_Object table = Fgethash (attribute,
3796                                 Vchar_attribute_hash_table, Qunbound);
3797   Lisp_Char_Table *ct;
3798 #ifdef HAVE_LIBCHISE
3799   CHISE_Feature feature;
3800 #else /* HAVE_LIBCHISE */
3801   Lisp_Object db_file;
3802   Lisp_Object db;
3803 #endif /* not HAVE_LIBCHISE */
3804
3805   if (CHAR_TABLEP (table))
3806     ct = XCHAR_TABLE (table);
3807   else
3808     return Qnil;
3809
3810 #ifdef HAVE_LIBCHISE
3811   if ( open_chise_data_source_maybe () )
3812     return -1;
3813   feature
3814     = chise_ds_get_feature (default_chise_data_source,
3815                             XSTRING_DATA (Fsymbol_name (attribute)));
3816 #else /* HAVE_LIBCHISE */
3817   db_file = char_attribute_system_db_file (Qsystem_char_id, attribute, 1);
3818   db = Fopen_database (db_file, Qnil, Qnil, build_string ("w+"), Qnil);
3819 #endif /* not HAVE_LIBCHISE */
3820   if (
3821 #ifdef HAVE_LIBCHISE
3822       feature != NULL
3823 #else /* HAVE_LIBCHISE */
3824       !NILP (db)
3825 #endif /* not HAVE_LIBCHISE */
3826       )
3827     {
3828       Lisp_Object (*filter)(Lisp_Object value);
3829
3830       if ( EQ (attribute, Qideographic_structure)
3831            || EQ (attribute, Q_identical)
3832            || EQ (attribute, Q_identical_from)
3833            || EQ (attribute, Q_same)
3834            || EQ (attribute, Q_same_of)
3835            || !NILP (Fstring_match
3836                      (build_string ("^\\(<-\\|->\\)simplified[^*]*$"),
3837                       Fsymbol_name (attribute),
3838                       Qnil, Qnil)) )
3839         filter = &Fchar_refs_simplify_char_specs;
3840       else
3841         filter = NULL;
3842
3843       if (UINT8_BYTE_TABLE_P (ct->table))
3844         save_uint8_byte_table (XUINT8_BYTE_TABLE(ct->table), ct,
3845 #ifdef HAVE_LIBCHISE
3846                                feature,
3847 #else /* HAVE_LIBCHISE */
3848                                db,
3849 #endif /* not HAVE_LIBCHISE */
3850                                0, 3, filter);
3851       else if (UINT16_BYTE_TABLE_P (ct->table))
3852         save_uint16_byte_table (XUINT16_BYTE_TABLE(ct->table), ct,
3853 #ifdef HAVE_LIBCHISE
3854                                 feature,
3855 #else /* HAVE_LIBCHISE */
3856                                 db,
3857 #endif /* not HAVE_LIBCHISE */
3858                                 0, 3, filter);
3859       else if (BYTE_TABLE_P (ct->table))
3860         save_byte_table (XBYTE_TABLE(ct->table), ct,
3861 #ifdef HAVE_LIBCHISE
3862                          feature,
3863 #else /* HAVE_LIBCHISE */
3864                          db,
3865 #endif /* not HAVE_LIBCHISE */
3866                          0, 3, filter);
3867 #ifdef HAVE_LIBCHISE
3868       chise_feature_sync (feature);
3869 #else /* HAVE_LIBCHISE */
3870       Fclose_database (db);
3871 #endif /* not HAVE_LIBCHISE */
3872       return Qt;
3873     }
3874   else
3875     return Qnil;
3876 }
3877
3878 DEFUN ("mount-char-attribute-table", Fmount_char_attribute_table, 1, 1, 0, /*
3879 Mount database file on char-attribute-table ATTRIBUTE.
3880 */
3881        (attribute))
3882 {
3883   Lisp_Object table = Fgethash (attribute,
3884                                 Vchar_attribute_hash_table, Qunbound);
3885
3886   if (UNBOUNDP (table))
3887     {
3888       Lisp_Char_Table *ct;
3889
3890       table = make_char_id_table (Qunbound);
3891       Fputhash (attribute, table, Vchar_attribute_hash_table);
3892       XCHAR_TABLE_NAME(table) = attribute;
3893       ct = XCHAR_TABLE (table);
3894       ct->table = Qunloaded;
3895       XCHAR_TABLE_UNLOADED(table) = 1;
3896 #ifndef HAVE_LIBCHISE
3897       ct->db = Qnil;
3898 #endif /* not HAVE_LIBCHISE */
3899       return Qt;
3900     }
3901   return Qnil;
3902 }
3903
3904 DEFUN ("close-char-attribute-table", Fclose_char_attribute_table, 1, 1, 0, /*
3905 Close database of ATTRIBUTE.
3906 */
3907        (attribute))
3908 {
3909   Lisp_Object table = Fgethash (attribute,
3910                                 Vchar_attribute_hash_table, Qunbound);
3911   Lisp_Char_Table *ct;
3912
3913   if (CHAR_TABLEP (table))
3914     ct = XCHAR_TABLE (table);
3915   else
3916     return Qnil;
3917   char_table_close_db_maybe (ct);
3918   return Qnil;
3919 }
3920
3921 DEFUN ("reset-char-attribute-table", Freset_char_attribute_table, 1, 1, 0, /*
3922 Reset values of ATTRIBUTE with database file.
3923 */
3924        (attribute))
3925 {
3926 #ifdef HAVE_LIBCHISE
3927   CHISE_Feature feature
3928     = chise_ds_get_feature (default_chise_data_source,
3929                             XSTRING_DATA (Fsymbol_name
3930                                           (attribute)));
3931
3932   if (feature == NULL)
3933     return Qnil;
3934
3935   if (chise_feature_setup_db (feature, 0) == 0)
3936     {
3937       Lisp_Object table = Fgethash (attribute,
3938                                     Vchar_attribute_hash_table, Qunbound);
3939       Lisp_Char_Table *ct;
3940
3941       chise_feature_sync (feature);
3942       if (UNBOUNDP (table))
3943         {
3944           table = make_char_id_table (Qunbound);
3945           Fputhash (attribute, table, Vchar_attribute_hash_table);
3946           XCHAR_TABLE_NAME(table) = attribute;
3947         }
3948       ct = XCHAR_TABLE (table);
3949       ct->table = Qunloaded;
3950       char_table_close_db_maybe (ct);
3951       XCHAR_TABLE_UNLOADED(table) = 1;
3952       return Qt;
3953     }
3954 #else
3955   Lisp_Object table = Fgethash (attribute,
3956                                 Vchar_attribute_hash_table, Qunbound);
3957   Lisp_Char_Table *ct;
3958   Lisp_Object db_file
3959     = char_attribute_system_db_file (Qsystem_char_id, attribute, 0);
3960
3961   if (!NILP (Ffile_exists_p (db_file)))
3962     {
3963       if (UNBOUNDP (table))
3964         {
3965           table = make_char_id_table (Qunbound);
3966           Fputhash (attribute, table, Vchar_attribute_hash_table);
3967           XCHAR_TABLE_NAME(table) = attribute;
3968         }
3969       ct = XCHAR_TABLE (table);
3970       ct->table = Qunloaded;
3971       char_table_close_db_maybe (ct);
3972       XCHAR_TABLE_UNLOADED(table) = 1;
3973       return Qt;
3974     }
3975 #endif
3976   return Qnil;
3977 }
3978
3979 Lisp_Object
3980 load_char_attribute_maybe (Lisp_Char_Table* cit, Emchar ch)
3981 {
3982   Lisp_Object attribute = CHAR_TABLE_NAME (cit);
3983
3984   if (!NILP (attribute))
3985     {
3986       Lisp_Object val;
3987
3988       if (char_table_open_db_maybe (cit))
3989         return Qunbound;
3990
3991       val = char_table_get_db (cit, ch);
3992
3993       if (!NILP (Vchar_db_stingy_mode))
3994         char_table_close_db_maybe (cit);
3995
3996       return val;
3997     }
3998   return Qunbound;
3999 }
4000
4001 Lisp_Char_Table* char_attribute_table_to_load;
4002
4003 #ifdef HAVE_LIBCHISE
4004 int
4005 load_char_attribute_table_map_func (CHISE_Char_ID cid,
4006                                     CHISE_Feature feature,
4007                                     CHISE_Value *value);
4008 int
4009 load_char_attribute_table_map_func (CHISE_Char_ID cid,
4010                                     CHISE_Feature feature,
4011                                     CHISE_Value *value)
4012 {
4013   Emchar code = cid;
4014   Lisp_Object ret = get_char_id_table_0 (char_attribute_table_to_load, code);
4015
4016   if (EQ (ret, Qunloaded))
4017     put_char_id_table_0 (char_attribute_table_to_load, code,
4018                          Fread (make_string ((Bufbyte *) value->data,
4019                                              value->size)));
4020   return 0;
4021 }
4022 #else /* HAVE_LIBCHISE */
4023 Lisp_Object Qload_char_attribute_table_map_function;
4024
4025 DEFUN ("load-char-attribute-table-map-function",
4026        Fload_char_attribute_table_map_function, 2, 2, 0, /*
4027 For internal use.  Don't use it.
4028 */
4029        (key, value))
4030 {
4031   Lisp_Object c = Fread (key);
4032   Emchar code = XCHAR (c);
4033   Lisp_Object ret = get_char_id_table_0 (char_attribute_table_to_load, code);
4034
4035   if (EQ (ret, Qunloaded))
4036     put_char_id_table_0 (char_attribute_table_to_load, code, Fread (value));
4037   return Qnil;
4038 }
4039 #endif /* not HAVE_LIBCHISE */
4040
4041 DEFUN ("load-char-attribute-table", Fload_char_attribute_table, 1, 1, 0, /*
4042 Load values of ATTRIBUTE into database file.
4043 */
4044        (attribute))
4045 {
4046   Lisp_Object table = Fgethash (attribute,
4047                                 Vchar_attribute_hash_table,
4048                                 Qunbound);
4049   if (CHAR_TABLEP (table))
4050     {
4051       Lisp_Char_Table *cit = XCHAR_TABLE (table);
4052
4053       if (char_table_open_db_maybe (cit))
4054         return Qnil;
4055
4056       char_attribute_table_to_load = XCHAR_TABLE (table);
4057       {
4058         struct gcpro gcpro1;
4059
4060         GCPRO1 (table);
4061 #ifdef HAVE_LIBCHISE
4062         chise_feature_foreach_char_with_value
4063           (chise_ds_get_feature (default_chise_data_source,
4064                                  XSTRING_DATA (Fsymbol_name (cit->name))),
4065            &load_char_attribute_table_map_func);
4066 #else /* HAVE_LIBCHISE */
4067         Fmap_database (Qload_char_attribute_table_map_function, cit->db);
4068 #endif /* not HAVE_LIBCHISE */
4069         UNGCPRO;
4070       }
4071       char_table_close_db_maybe (cit);
4072       XCHAR_TABLE_UNLOADED(table) = 0;
4073       return Qt;
4074     }
4075   return Qnil;
4076 }
4077 #endif /* HAVE_CHISE */
4078
4079 DEFUN ("map-char-attribute", Fmap_char_attribute, 2, 3, 0, /*
4080 Map FUNCTION over entries in ATTRIBUTE, calling it with two args,
4081 each key and value in the table.
4082
4083 RANGE specifies a subrange to map over and is in the same format as
4084 the RANGE argument to `put-range-table'.  If omitted or t, it defaults to
4085 the entire table.
4086 */
4087        (function, attribute, range))
4088 {
4089   Lisp_Object ccs;
4090   Lisp_Char_Table *ct;
4091   struct slow_map_char_table_arg slarg;
4092   struct gcpro gcpro1, gcpro2;
4093   struct chartab_range rainj;
4094
4095   if (!NILP (ccs = Ffind_charset (attribute)))
4096     {
4097       Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
4098
4099       if (CHAR_TABLEP (encoding_table))
4100         ct = XCHAR_TABLE (encoding_table);
4101       else
4102         return Qnil;
4103     }
4104   else
4105     {
4106       Lisp_Object table = Fgethash (attribute,
4107                                     Vchar_attribute_hash_table,
4108                                     Qunbound);
4109       if (CHAR_TABLEP (table))
4110         ct = XCHAR_TABLE (table);
4111       else
4112         return Qnil;
4113     }
4114   if (NILP (range))
4115     range = Qt;
4116   decode_char_table_range (range, &rainj);
4117 #ifdef HAVE_CHISE
4118   if (CHAR_TABLE_UNLOADED(ct))
4119     Fload_char_attribute_table (attribute);
4120 #endif
4121   slarg.function = function;
4122   slarg.retval = Qnil;
4123   GCPRO2 (slarg.function, slarg.retval);
4124   map_char_table (ct, &rainj, slow_map_char_table_fun, &slarg);
4125   UNGCPRO;
4126
4127   return slarg.retval;
4128 }
4129
4130 DEFUN ("define-char", Fdefine_char, 1, 1, 0, /*
4131 Store character's ATTRIBUTES.
4132 */
4133        (attributes))
4134 {
4135   Lisp_Object rest;
4136   Lisp_Object code = Fcdr (Fassq (Qmap_ucs, attributes));
4137   Lisp_Object character;
4138
4139   if (NILP (code))
4140     code = Fcdr (Fassq (Qucs, attributes));
4141
4142   if (NILP (code))
4143     {
4144       rest = attributes;
4145       while (CONSP (rest))
4146         {
4147           Lisp_Object cell = Fcar (rest);
4148           Lisp_Object ccs;
4149
4150           if ( !LISTP (cell) )
4151             signal_simple_error ("Invalid argument", attributes);
4152
4153           ccs = Ffind_charset (Fcar (cell));
4154           if (!NILP (ccs))
4155             {
4156               cell = Fcdr (cell);
4157               if (INTP (cell))
4158                 {
4159                   character = Fdecode_char (ccs, cell, Qt, Qt);
4160                   if (!NILP (character))
4161                     goto setup_attributes;
4162                 }
4163               if ( (XCHARSET_FINAL (ccs) != 0) ||
4164                    (XCHARSET_MAX_CODE (ccs) > 0) ||
4165                    (EQ (ccs, Vcharset_chinese_big5)) )
4166                 {
4167                   if (CONSP (cell))
4168                     character
4169                       = Fmake_char (ccs, Fcar (cell), Fcar (Fcdr (cell)));
4170                   else
4171                     character = Fdecode_char (ccs, cell, Qnil, Qt);
4172                   if (!NILP (character))
4173                     goto setup_attributes;
4174                 }
4175             }
4176           rest = Fcdr (rest);
4177         }
4178 #if 1
4179       {
4180         int cid = XINT (Vnext_defined_char_id);
4181
4182         if (cid <= 0xE00000)
4183           {
4184             character = make_char (cid);
4185             Vnext_defined_char_id = make_int (cid + 1);
4186             goto setup_attributes;
4187           }
4188       }
4189 #else
4190       if ( (!NILP (code = Fcdr (Fassq (Qto_ucs, attributes)))) )
4191         {
4192           if (!INTP (code))
4193             signal_simple_error ("Invalid argument", attributes);
4194           else
4195             character = make_char (XINT (code) + 0x100000);
4196           goto setup_attributes;
4197         }
4198 #endif
4199       return Qnil;
4200     }
4201   else if (!INTP (code))
4202     signal_simple_error ("Invalid argument", attributes);
4203   else
4204     character = make_char (XINT (code));
4205
4206  setup_attributes:
4207   rest = attributes;
4208   while (CONSP (rest))
4209     {
4210       Lisp_Object cell = Fcar (rest);
4211
4212       if (!LISTP (cell))
4213         signal_simple_error ("Invalid argument", attributes);
4214
4215       Fput_char_attribute (character, Fcar (cell), Fcdr (cell));
4216       rest = Fcdr (rest);
4217     }
4218   return character;
4219 }
4220
4221 DEFUN ("find-char", Ffind_char, 1, 1, 0, /*
4222 Retrieve the character of the given ATTRIBUTES.
4223 */
4224        (attributes))
4225 {
4226   Lisp_Object rest = attributes;
4227   Lisp_Object code;
4228
4229   while (CONSP (rest))
4230     {
4231       Lisp_Object cell = Fcar (rest);
4232       Lisp_Object ccs;
4233
4234       if (!LISTP (cell))
4235         signal_simple_error ("Invalid argument", attributes);
4236       if (!NILP (ccs = Ffind_charset (Fcar (cell))))
4237         {
4238           cell = Fcdr (cell);
4239           if (CONSP (cell))
4240             return Fmake_char (ccs, Fcar (cell), Fcar (Fcdr (cell)));
4241           else
4242             return Fdecode_char (ccs, cell, Qnil, Qnil);
4243         }
4244       rest = Fcdr (rest);
4245     }
4246   if ( (!NILP (code = Fcdr (Fassq (Qto_ucs, attributes)))) )
4247     {
4248       if (!INTP (code))
4249         signal_simple_error ("Invalid argument", attributes);
4250       else
4251         return make_char (XINT (code) + 0x100000);
4252     }
4253   return Qnil;
4254 }
4255
4256 #endif
4257
4258 \f
4259 /************************************************************************/
4260 /*                         Char table read syntax                       */
4261 /************************************************************************/
4262
4263 static int
4264 chartab_type_validate (Lisp_Object keyword, Lisp_Object value,
4265                        Error_behavior errb)
4266 {
4267   /* #### should deal with ERRB */
4268   symbol_to_char_table_type (value);
4269   return 1;
4270 }
4271
4272 static int
4273 chartab_data_validate (Lisp_Object keyword, Lisp_Object value,
4274                        Error_behavior errb)
4275 {
4276   Lisp_Object rest;
4277
4278   /* #### should deal with ERRB */
4279   EXTERNAL_LIST_LOOP (rest, value)
4280     {
4281       Lisp_Object range = XCAR (rest);
4282       struct chartab_range dummy;
4283
4284       rest = XCDR (rest);
4285       if (!CONSP (rest))
4286         signal_simple_error ("Invalid list format", value);
4287       if (CONSP (range))
4288         {
4289           if (!CONSP (XCDR (range))
4290               || !NILP (XCDR (XCDR (range))))
4291             signal_simple_error ("Invalid range format", range);
4292           decode_char_table_range (XCAR (range), &dummy);
4293           decode_char_table_range (XCAR (XCDR (range)), &dummy);
4294         }
4295       else
4296         decode_char_table_range (range, &dummy);
4297     }
4298
4299   return 1;
4300 }
4301
4302 static Lisp_Object
4303 chartab_instantiate (Lisp_Object data)
4304 {
4305   Lisp_Object chartab;
4306   Lisp_Object type = Qgeneric;
4307   Lisp_Object dataval = Qnil;
4308
4309   while (!NILP (data))
4310     {
4311       Lisp_Object keyw = Fcar (data);
4312       Lisp_Object valw;
4313
4314       data = Fcdr (data);
4315       valw = Fcar (data);
4316       data = Fcdr (data);
4317       if (EQ (keyw, Qtype))
4318         type = valw;
4319       else if (EQ (keyw, Qdata))
4320         dataval = valw;
4321     }
4322
4323   chartab = Fmake_char_table (type);
4324
4325   data = dataval;
4326   while (!NILP (data))
4327     {
4328       Lisp_Object range = Fcar (data);
4329       Lisp_Object val = Fcar (Fcdr (data));
4330
4331       data = Fcdr (Fcdr (data));
4332       if (CONSP (range))
4333         {
4334           if (CHAR_OR_CHAR_INTP (XCAR (range)))
4335             {
4336               Emchar first = XCHAR_OR_CHAR_INT (Fcar (range));
4337               Emchar last = XCHAR_OR_CHAR_INT (Fcar (Fcdr (range)));
4338               Emchar i;
4339
4340               for (i = first; i <= last; i++)
4341                  Fput_char_table (make_char (i), val, chartab);
4342             }
4343           else
4344             abort ();
4345         }
4346       else
4347         Fput_char_table (range, val, chartab);
4348     }
4349
4350   return chartab;
4351 }
4352
4353 #ifdef MULE
4354
4355 \f
4356 /************************************************************************/
4357 /*                     Category Tables, specifically                    */
4358 /************************************************************************/
4359
4360 DEFUN ("category-table-p", Fcategory_table_p, 1, 1, 0, /*
4361 Return t if OBJECT is a category table.
4362 A category table is a type of char table used for keeping track of
4363 categories.  Categories are used for classifying characters for use
4364 in regexps -- you can refer to a category rather than having to use
4365 a complicated [] expression (and category lookups are significantly
4366 faster).
4367
4368 There are 95 different categories available, one for each printable
4369 character (including space) in the ASCII charset.  Each category
4370 is designated by one such character, called a "category designator".
4371 They are specified in a regexp using the syntax "\\cX", where X is
4372 a category designator.
4373
4374 A category table specifies, for each character, the categories that
4375 the character is in.  Note that a character can be in more than one
4376 category.  More specifically, a category table maps from a character
4377 to either the value nil (meaning the character is in no categories)
4378 or a 95-element bit vector, specifying for each of the 95 categories
4379 whether the character is in that category.
4380
4381 Special Lisp functions are provided that abstract this, so you do not
4382 have to directly manipulate bit vectors.
4383 */
4384        (object))
4385 {
4386   return (CHAR_TABLEP (object) &&
4387           XCHAR_TABLE_TYPE (object) == CHAR_TABLE_TYPE_CATEGORY) ?
4388     Qt : Qnil;
4389 }
4390
4391 static Lisp_Object
4392 check_category_table (Lisp_Object object, Lisp_Object default_)
4393 {
4394   if (NILP (object))
4395     object = default_;
4396   while (NILP (Fcategory_table_p (object)))
4397     object = wrong_type_argument (Qcategory_table_p, object);
4398   return object;
4399 }
4400
4401 int
4402 check_category_char (Emchar ch, Lisp_Object table,
4403                      unsigned int designator, unsigned int not_p)
4404 {
4405   REGISTER Lisp_Object temp;
4406   Lisp_Char_Table *ctbl;
4407 #ifdef ERROR_CHECK_TYPECHECK
4408   if (NILP (Fcategory_table_p (table)))
4409     signal_simple_error ("Expected category table", table);
4410 #endif
4411   ctbl = XCHAR_TABLE (table);
4412   temp = get_char_table (ch, ctbl);
4413   if (NILP (temp))
4414     return not_p;
4415
4416   designator -= ' ';
4417   return bit_vector_bit (XBIT_VECTOR (temp), designator) ? !not_p : not_p;
4418 }
4419
4420 DEFUN ("check-category-at", Fcheck_category_at, 2, 4, 0, /*
4421 Return t if category of the character at POSITION includes DESIGNATOR.
4422 Optional third arg BUFFER specifies which buffer to use, and defaults
4423 to the current buffer.
4424 Optional fourth arg CATEGORY-TABLE specifies the category table to
4425 use, and defaults to BUFFER's category table.
4426 */
4427        (position, designator, buffer, category_table))
4428 {
4429   Lisp_Object ctbl;
4430   Emchar ch;
4431   unsigned int des;
4432   struct buffer *buf = decode_buffer (buffer, 0);
4433
4434   CHECK_INT (position);
4435   CHECK_CATEGORY_DESIGNATOR (designator);
4436   des = XCHAR (designator);
4437   ctbl = check_category_table (category_table, Vstandard_category_table);
4438   ch = BUF_FETCH_CHAR (buf, XINT (position));
4439   return check_category_char (ch, ctbl, des, 0) ? Qt : Qnil;
4440 }
4441
4442 DEFUN ("char-in-category-p", Fchar_in_category_p, 2, 3, 0, /*
4443 Return t if category of CHARACTER includes DESIGNATOR, else nil.
4444 Optional third arg CATEGORY-TABLE specifies the category table to use,
4445 and defaults to the standard category table.
4446 */
4447        (character, designator, category_table))
4448 {
4449   Lisp_Object ctbl;
4450   Emchar ch;
4451   unsigned int des;
4452
4453   CHECK_CATEGORY_DESIGNATOR (designator);
4454   des = XCHAR (designator);
4455   CHECK_CHAR (character);
4456   ch = XCHAR (character);
4457   ctbl = check_category_table (category_table, Vstandard_category_table);
4458   return check_category_char (ch, ctbl, des, 0) ? Qt : Qnil;
4459 }
4460
4461 DEFUN ("category-table", Fcategory_table, 0, 1, 0, /*
4462 Return BUFFER's current category table.
4463 BUFFER defaults to the current buffer.
4464 */
4465        (buffer))
4466 {
4467   return decode_buffer (buffer, 0)->category_table;
4468 }
4469
4470 DEFUN ("standard-category-table", Fstandard_category_table, 0, 0, 0, /*
4471 Return the standard category table.
4472 This is the one used for new buffers.
4473 */
4474        ())
4475 {
4476   return Vstandard_category_table;
4477 }
4478
4479 DEFUN ("copy-category-table", Fcopy_category_table, 0, 1, 0, /*
4480 Return a new category table which is a copy of CATEGORY-TABLE.
4481 CATEGORY-TABLE defaults to the standard category table.
4482 */
4483        (category_table))
4484 {
4485   if (NILP (Vstandard_category_table))
4486     return Fmake_char_table (Qcategory);
4487
4488   category_table =
4489     check_category_table (category_table, Vstandard_category_table);
4490   return Fcopy_char_table (category_table);
4491 }
4492
4493 DEFUN ("set-category-table", Fset_category_table, 1, 2, 0, /*
4494 Select CATEGORY-TABLE as the new category table for BUFFER.
4495 BUFFER defaults to the current buffer if omitted.
4496 */
4497        (category_table, buffer))
4498 {
4499   struct buffer *buf = decode_buffer (buffer, 0);
4500   category_table = check_category_table (category_table, Qnil);
4501   buf->category_table = category_table;
4502   /* Indicate that this buffer now has a specified category table.  */
4503   buf->local_var_flags |= XINT (buffer_local_flags.category_table);
4504   return category_table;
4505 }
4506
4507 DEFUN ("category-designator-p", Fcategory_designator_p, 1, 1, 0, /*
4508 Return t if OBJECT is a category designator (a char in the range ' ' to '~').
4509 */
4510        (object))
4511 {
4512   return CATEGORY_DESIGNATORP (object) ? Qt : Qnil;
4513 }
4514
4515 DEFUN ("category-table-value-p", Fcategory_table_value_p, 1, 1, 0, /*
4516 Return t if OBJECT is a category table value.
4517 Valid values are nil or a bit vector of size 95.
4518 */
4519        (object))
4520 {
4521   return CATEGORY_TABLE_VALUEP (object) ? Qt : Qnil;
4522 }
4523
4524
4525 #define CATEGORYP(x) \
4526   (CHARP (x) && XCHAR (x) >= 0x20 && XCHAR (x) <= 0x7E)
4527
4528 #define CATEGORY_SET(c)                                         \
4529   (get_char_table(c, XCHAR_TABLE(current_buffer->category_table)))
4530
4531 /* Return 1 if CATEGORY_SET contains CATEGORY, else return 0.
4532    The faster version of `!NILP (Faref (category_set, category))'.  */
4533 #define CATEGORY_MEMBER(category, category_set)                 \
4534   (bit_vector_bit(XBIT_VECTOR (category_set), category - 32))
4535
4536 /* Return 1 if there is a word boundary between two word-constituent
4537    characters C1 and C2 if they appear in this order, else return 0.
4538    Use the macro WORD_BOUNDARY_P instead of calling this function
4539    directly.  */
4540
4541 int word_boundary_p (Emchar c1, Emchar c2);
4542 int
4543 word_boundary_p (Emchar c1, Emchar c2)
4544 {
4545   Lisp_Object category_set1, category_set2;
4546   Lisp_Object tail;
4547   int default_result;
4548
4549 #if 0
4550   if (COMPOSITE_CHAR_P (c1))
4551     c1 = cmpchar_component (c1, 0, 1);
4552   if (COMPOSITE_CHAR_P (c2))
4553     c2 = cmpchar_component (c2, 0, 1);
4554 #endif
4555
4556 #ifndef UTF2000
4557   if (EQ (CHAR_CHARSET (c1), CHAR_CHARSET (c2)))
4558 #endif
4559     {
4560       tail = Vword_separating_categories;
4561       default_result = 0;
4562     }
4563 #ifndef UTF2000
4564   else
4565     {
4566       tail = Vword_combining_categories;
4567       default_result = 1;
4568     }
4569 #endif
4570
4571   category_set1 = CATEGORY_SET (c1);
4572   if (NILP (category_set1))
4573     return default_result;
4574   category_set2 = CATEGORY_SET (c2);
4575   if (NILP (category_set2))
4576     return default_result;
4577
4578   for (; CONSP (tail); tail = XCONS (tail)->cdr)
4579     {
4580       Lisp_Object elt = XCONS(tail)->car;
4581
4582       if (CONSP (elt)
4583           && CATEGORYP (XCONS (elt)->car)
4584           && CATEGORYP (XCONS (elt)->cdr)
4585           && CATEGORY_MEMBER (XCHAR (XCONS (elt)->car), category_set1)
4586           && CATEGORY_MEMBER (XCHAR (XCONS (elt)->cdr), category_set2))
4587         return !default_result;
4588     }
4589   return default_result;
4590 }
4591 #endif /* MULE */
4592
4593 \f
4594 void
4595 syms_of_chartab (void)
4596 {
4597 #ifdef UTF2000
4598   INIT_LRECORD_IMPLEMENTATION (uint8_byte_table);
4599   INIT_LRECORD_IMPLEMENTATION (uint16_byte_table);
4600   INIT_LRECORD_IMPLEMENTATION (byte_table);
4601
4602   defsymbol (&Qto_ucs,                  "=>ucs");
4603   defsymbol (&Q_ucs_unified,            "->ucs-unified");
4604   defsymbol (&Q_subsumptive,            "->subsumptive");
4605   defsymbol (&Q_subsumptive_from,       "<-subsumptive");
4606   defsymbol (&Q_denotational,           "->denotational");
4607   defsymbol (&Q_denotational_from,      "<-denotational");
4608   defsymbol (&Q_identical,              "->identical");
4609   defsymbol (&Q_identical_from,         "<-identical");
4610   defsymbol (&Q_component,              "->ideographic-component-forms");
4611   defsymbol (&Q_component_of,           "<-ideographic-component-forms");
4612   defsymbol (&Q_same,                   "->same");
4613   defsymbol (&Q_same_of,                "<-same");
4614   defsymbol (&Qcomposition,             "composition");
4615   defsymbol (&Q_decomposition,          "->decomposition");
4616   defsymbol (&Qcompat,                  "compat");
4617   defsymbol (&Qisolated,                "isolated");
4618   defsymbol (&Qinitial,                 "initial");
4619   defsymbol (&Qmedial,                  "medial");
4620   defsymbol (&Qfinal,                   "final");
4621   defsymbol (&Qvertical,                "vertical");
4622   defsymbol (&QnoBreak,                 "noBreak");
4623   defsymbol (&Qfraction,                "fraction");
4624   defsymbol (&Qsuper,                   "super");
4625   defsymbol (&Qsub,                     "sub");
4626   defsymbol (&Qcircle,                  "circle");
4627   defsymbol (&Qsquare,                  "square");
4628   defsymbol (&Qwide,                    "wide");
4629   defsymbol (&Qnarrow,                  "narrow");
4630   defsymbol (&Qsmall,                   "small");
4631   defsymbol (&Qfont,                    "font");
4632
4633   DEFSUBR (Fchar_attribute_list);
4634   DEFSUBR (Ffind_char_attribute_table);
4635   defsymbol (&Qput_char_table_map_function, "put-char-table-map-function");
4636   DEFSUBR (Fput_char_table_map_function);
4637 #ifdef HAVE_CHISE
4638   DEFSUBR (Fsave_char_attribute_table);
4639   DEFSUBR (Fmount_char_attribute_table);
4640   DEFSUBR (Freset_char_attribute_table);
4641   DEFSUBR (Fclose_char_attribute_table);
4642   DEFSUBR (Fclose_char_data_source);
4643 #ifndef HAVE_LIBCHISE
4644   defsymbol (&Qload_char_attribute_table_map_function,
4645              "load-char-attribute-table-map-function");
4646   DEFSUBR (Fload_char_attribute_table_map_function);
4647 #endif
4648   DEFSUBR (Fload_char_attribute_table);
4649 #endif
4650   DEFSUBR (Fchar_feature);
4651   DEFSUBR (Fchar_attribute_alist);
4652   DEFSUBR (Fget_char_attribute);
4653   DEFSUBR (Fput_char_attribute);
4654   DEFSUBR (Fremove_char_attribute);
4655   DEFSUBR (Fmap_char_attribute);
4656   DEFSUBR (Fdefine_char);
4657   DEFSUBR (Ffind_char);
4658   DEFSUBR (Fchar_variants);
4659
4660   DEFSUBR (Fget_composite_char);
4661 #endif
4662
4663   INIT_LRECORD_IMPLEMENTATION (char_table);
4664
4665 #ifdef MULE
4666 #ifndef UTF2000
4667   INIT_LRECORD_IMPLEMENTATION (char_table_entry);
4668 #endif
4669
4670   defsymbol (&Qcategory_table_p, "category-table-p");
4671   defsymbol (&Qcategory_designator_p, "category-designator-p");
4672   defsymbol (&Qcategory_table_value_p, "category-table-value-p");
4673 #endif /* MULE */
4674
4675   defsymbol (&Qchar_table, "char-table");
4676   defsymbol (&Qchar_tablep, "char-table-p");
4677
4678   DEFSUBR (Fchar_table_p);
4679   DEFSUBR (Fchar_table_type_list);
4680   DEFSUBR (Fvalid_char_table_type_p);
4681   DEFSUBR (Fchar_table_type);
4682   DEFSUBR (Freset_char_table);
4683   DEFSUBR (Fmake_char_table);
4684   DEFSUBR (Fcopy_char_table);
4685   DEFSUBR (Fget_char_table);
4686   DEFSUBR (Fget_range_char_table);
4687   DEFSUBR (Fvalid_char_table_value_p);
4688   DEFSUBR (Fcheck_valid_char_table_value);
4689   DEFSUBR (Fput_char_table);
4690   DEFSUBR (Fmap_char_table);
4691
4692 #ifdef MULE
4693   DEFSUBR (Fcategory_table_p);
4694   DEFSUBR (Fcategory_table);
4695   DEFSUBR (Fstandard_category_table);
4696   DEFSUBR (Fcopy_category_table);
4697   DEFSUBR (Fset_category_table);
4698   DEFSUBR (Fcheck_category_at);
4699   DEFSUBR (Fchar_in_category_p);
4700   DEFSUBR (Fcategory_designator_p);
4701   DEFSUBR (Fcategory_table_value_p);
4702 #endif /* MULE */
4703
4704 }
4705
4706 void
4707 vars_of_chartab (void)
4708 {
4709 #ifdef UTF2000
4710   DEFVAR_LISP ("next-defined-char-id", &Vnext_defined_char_id /*
4711 */ );
4712   Vnext_defined_char_id = make_int (0x0F0000);
4713 #endif
4714
4715 #ifdef HAVE_CHISE
4716   DEFVAR_LISP ("char-db-stingy-mode", &Vchar_db_stingy_mode /*
4717 */ );
4718   Vchar_db_stingy_mode = Qt;
4719
4720 #ifdef HAVE_LIBCHISE
4721   Vchise_db_directory = build_string(chise_db_dir);
4722   DEFVAR_LISP ("chise-db-directory", &Vchise_db_directory /*
4723 Directory of CHISE character databases.
4724 */ );
4725
4726   Vchise_system_db_directory = build_string(chise_system_db_dir);
4727   DEFVAR_LISP ("chise-system-db-directory", &Vchise_system_db_directory /*
4728 Directory of system character database of CHISE.
4729 */ );
4730 #endif
4731
4732 #endif /* HAVE_CHISE */
4733   /* DO NOT staticpro this.  It works just like Vweak_hash_tables. */
4734   Vall_syntax_tables = Qnil;
4735   dump_add_weak_object_chain (&Vall_syntax_tables);
4736 }
4737
4738 void
4739 structure_type_create_chartab (void)
4740 {
4741   struct structure_type *st;
4742
4743   st = define_structure_type (Qchar_table, 0, chartab_instantiate);
4744
4745   define_structure_type_keyword (st, Qtype, chartab_type_validate);
4746   define_structure_type_keyword (st, Qdata, chartab_data_validate);
4747 }
4748
4749 void
4750 complex_vars_of_chartab (void)
4751 {
4752 #ifdef UTF2000
4753   staticpro (&Vchar_attribute_hash_table);
4754   Vchar_attribute_hash_table
4755     = make_lisp_hash_table (16, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
4756 #endif /* UTF2000 */
4757 #ifdef MULE
4758   /* Set this now, so first buffer creation can refer to it. */
4759   /* Make it nil before calling copy-category-table
4760      so that copy-category-table will know not to try to copy from garbage */
4761   Vstandard_category_table = Qnil;
4762   Vstandard_category_table = Fcopy_category_table (Qnil);
4763   staticpro (&Vstandard_category_table);
4764
4765   DEFVAR_LISP ("word-combining-categories", &Vword_combining_categories /*
4766 List of pair (cons) of categories to determine word boundary.
4767
4768 Emacs treats a sequence of word constituent characters as a single
4769 word (i.e. finds no word boundary between them) iff they belongs to
4770 the same charset.  But, exceptions are allowed in the following cases.
4771
4772 \(1) The case that characters are in different charsets is controlled
4773 by the variable `word-combining-categories'.
4774
4775 Emacs finds no word boundary between characters of different charsets
4776 if they have categories matching some element of this list.
4777
4778 More precisely, if an element of this list is a cons of category CAT1
4779 and CAT2, and a multibyte character C1 which has CAT1 is followed by
4780 C2 which has CAT2, there's no word boundary between C1 and C2.
4781
4782 For instance, to tell that ASCII characters and Latin-1 characters can
4783 form a single word, the element `(?l . ?l)' should be in this list
4784 because both characters have the category `l' (Latin characters).
4785
4786 \(2) The case that character are in the same charset is controlled by
4787 the variable `word-separating-categories'.
4788
4789 Emacs find a word boundary between characters of the same charset
4790 if they have categories matching some element of this list.
4791
4792 More precisely, if an element of this list is a cons of category CAT1
4793 and CAT2, and a multibyte character C1 which has CAT1 is followed by
4794 C2 which has CAT2, there's a word boundary between C1 and C2.
4795
4796 For instance, to tell that there's a word boundary between Japanese
4797 Hiragana and Japanese Kanji (both are in the same charset), the
4798 element `(?H . ?C) should be in this list.
4799 */ );
4800
4801   Vword_combining_categories = Qnil;
4802
4803   DEFVAR_LISP ("word-separating-categories", &Vword_separating_categories /*
4804 List of pair (cons) of categories to determine word boundary.
4805 See the documentation of the variable `word-combining-categories'.
4806 */ );
4807
4808   Vword_separating_categories = Qnil;
4809 #endif /* MULE */
4810 }