(map_over_uint8_byte_table): Change arguments; add new argument `ccs'.
[chise/xemacs-chise.git-] / 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
8 This file is part of XEmacs.
9
10 XEmacs is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option) any
13 later version.
14
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with XEmacs; see the file COPYING.  If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.  */
24
25 /* Synched up with: Mule 2.3.  Not synched with FSF.
26
27    This file was written independently of the FSF implementation,
28    and is not compatible. */
29
30 /* Authorship:
31
32    Ben Wing: wrote, for 19.13 (Mule).  Some category table stuff
33              loosely based on the original Mule.
34    Jareth Hein: fixed a couple of bugs in the implementation, and
35              added regex support for categories with check_category_at
36  */
37
38 #include <config.h>
39 #include "lisp.h"
40
41 #include "buffer.h"
42 #include "chartab.h"
43 #include "syntax.h"
44
45 #ifdef UTF2000
46 #include "elhash.h"
47
48 Lisp_Object Vutf_2000_version;
49 #endif /* UTF2000 */
50
51 Lisp_Object Qchar_tablep, Qchar_table;
52
53 Lisp_Object Vall_syntax_tables;
54
55 #ifdef MULE
56 Lisp_Object Qcategory_table_p;
57 Lisp_Object Qcategory_designator_p;
58 Lisp_Object Qcategory_table_value_p;
59
60 Lisp_Object Vstandard_category_table;
61
62 /* Variables to determine word boundary.  */
63 Lisp_Object Vword_combining_categories, Vword_separating_categories;
64 #endif /* MULE */
65
66 \f
67 #ifdef UTF2000
68
69 #define BT_UINT8_MIN            0
70 #define BT_UINT8_MAX    (UCHAR_MAX - 3)
71 #define BT_UINT8_t      (UCHAR_MAX - 2)
72 #define BT_UINT8_nil    (UCHAR_MAX - 1)
73 #define BT_UINT8_unbound UCHAR_MAX
74
75 INLINE_HEADER int INT_UINT8_P (Lisp_Object obj);
76 INLINE_HEADER int UINT8_VALUE_P (Lisp_Object obj);
77 INLINE_HEADER unsigned char UINT8_ENCODE (Lisp_Object obj);
78 INLINE_HEADER Lisp_Object UINT8_DECODE (unsigned char n);
79 INLINE_HEADER unsigned short UINT8_TO_UINT16 (unsigned char n);
80
81 INLINE_HEADER int
82 INT_UINT8_P (Lisp_Object obj)
83 {
84   if (INTP (obj))
85     {
86       int num = XINT (obj);
87
88       return (BT_UINT8_MIN <= num) && (num <= BT_UINT8_MAX);
89     }
90   else
91     return 0;
92 }
93
94 INLINE_HEADER int
95 UINT8_VALUE_P (Lisp_Object obj)
96 {
97   return EQ (obj, Qunbound)
98     || EQ (obj, Qnil) || EQ (obj, Qt) || INT_UINT8_P (obj);
99 }
100
101 INLINE_HEADER unsigned char
102 UINT8_ENCODE (Lisp_Object obj)
103 {
104   if (EQ (obj, Qunbound))
105     return BT_UINT8_unbound;
106   else if (EQ (obj, Qnil))
107     return BT_UINT8_nil;
108   else if (EQ (obj, Qt))
109     return BT_UINT8_t;
110   else
111     return XINT (obj);
112 }
113
114 INLINE_HEADER Lisp_Object
115 UINT8_DECODE (unsigned char n)
116 {
117   if (n == BT_UINT8_unbound)
118     return Qunbound;
119   else if (n == BT_UINT8_nil)
120     return Qnil;
121   else if (n == BT_UINT8_t)
122     return Qt;
123   else
124     return make_int (n);
125 }
126
127 static Lisp_Object
128 mark_uint8_byte_table (Lisp_Object obj)
129 {
130   return Qnil;
131 }
132
133 static void
134 print_uint8_byte_table (Lisp_Object obj,
135                         Lisp_Object printcharfun, int escapeflag)
136 {
137   Lisp_Uint8_Byte_Table *bte = XUINT8_BYTE_TABLE (obj);
138   int i;
139   struct gcpro gcpro1, gcpro2;
140   GCPRO2 (obj, printcharfun);
141
142   write_c_string ("\n#<uint8-byte-table", printcharfun);
143   for (i = 0; i < 256; i++)
144     {
145       unsigned char n = bte->property[i];
146       if ( (i & 15) == 0 )
147         write_c_string ("\n  ", printcharfun);
148       write_c_string (" ", printcharfun);
149       if (n == BT_UINT8_unbound)
150         write_c_string ("void", printcharfun);
151       else if (n == BT_UINT8_nil)
152         write_c_string ("nil", printcharfun);
153       else if (n == BT_UINT8_t)
154         write_c_string ("t", printcharfun);
155       else
156         {
157           char buf[4];
158
159           sprintf (buf, "%hd", n);
160           write_c_string (buf, printcharfun);
161         }
162     }
163   UNGCPRO;
164   write_c_string (">", printcharfun);
165 }
166
167 static int
168 uint8_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
169 {
170   Lisp_Uint8_Byte_Table *te1 = XUINT8_BYTE_TABLE (obj1);
171   Lisp_Uint8_Byte_Table *te2 = XUINT8_BYTE_TABLE (obj2);
172   int i;
173
174   for (i = 0; i < 256; i++)
175     if (te1->property[i] != te2->property[i])
176       return 0;
177   return 1;
178 }
179
180 static unsigned long
181 uint8_byte_table_hash (Lisp_Object obj, int depth)
182 {
183   Lisp_Uint8_Byte_Table *te = XUINT8_BYTE_TABLE (obj);
184   int i;
185   hashcode_t hash = 0;
186
187   for (i = 0; i < 256; i++)
188     hash = HASH2 (hash, te->property[i]);
189   return hash;
190 }
191
192 DEFINE_LRECORD_IMPLEMENTATION ("uint8-byte-table", uint8_byte_table,
193                                mark_uint8_byte_table,
194                                print_uint8_byte_table,
195                                0, uint8_byte_table_equal,
196                                uint8_byte_table_hash,
197                                0 /* uint8_byte_table_description */,
198                                Lisp_Uint8_Byte_Table);
199
200 static Lisp_Object
201 make_uint8_byte_table (unsigned char initval)
202 {
203   Lisp_Object obj;
204   int i;
205   Lisp_Uint8_Byte_Table *cte;
206
207   cte = alloc_lcrecord_type (Lisp_Uint8_Byte_Table,
208                              &lrecord_uint8_byte_table);
209
210   for (i = 0; i < 256; i++)
211     cte->property[i] = initval;
212
213   XSETUINT8_BYTE_TABLE (obj, cte);
214   return obj;
215 }
216
217 static int
218 uint8_byte_table_same_value_p (Lisp_Object obj)
219 {
220   Lisp_Uint8_Byte_Table *bte = XUINT8_BYTE_TABLE (obj);
221   unsigned char v0 = bte->property[0];
222   int i;
223
224   for (i = 1; i < 256; i++)
225     {
226       if (bte->property[i] != v0)
227         return 0;
228     }
229   return -1;
230 }
231
232 static int
233 map_over_uint8_byte_table (Lisp_Uint8_Byte_Table *ct, Emchar ofs, int place,
234                            Lisp_Object ccs,
235                            int (*fn) (struct chartab_range *range,
236                                       Lisp_Object val, void *arg),
237                            void *arg)
238 {
239   struct chartab_range rainj;
240   int i, retval;
241   int unit = 1 << (8 * place);
242   Emchar c = ofs;
243   Emchar c1;
244
245   rainj.type = CHARTAB_RANGE_CHAR;
246
247   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
248     {
249       if (ct->property[i] != BT_UINT8_unbound)
250         {
251           c1 = c + unit;
252           for (; c < c1 && retval == 0; c++)
253             {
254               if ( NILP (ccs) || charset_code_point (ccs, c) >= 0 )
255                 {
256                   rainj.ch = c;
257                   retval = (fn) (&rainj, UINT8_DECODE (ct->property[i]), arg);
258                 }
259             }
260         }
261       else
262         c += unit;
263     }
264   return retval;
265 }
266
267 #define BT_UINT16_MIN           0
268 #define BT_UINT16_MAX    (USHRT_MAX - 3)
269 #define BT_UINT16_t      (USHRT_MAX - 2)
270 #define BT_UINT16_nil    (USHRT_MAX - 1)
271 #define BT_UINT16_unbound USHRT_MAX
272
273 INLINE_HEADER int INT_UINT16_P (Lisp_Object obj);
274 INLINE_HEADER int UINT16_VALUE_P (Lisp_Object obj);
275 INLINE_HEADER unsigned short UINT16_ENCODE (Lisp_Object obj);
276 INLINE_HEADER Lisp_Object UINT16_DECODE (unsigned short us);
277
278 INLINE_HEADER int
279 INT_UINT16_P (Lisp_Object obj)
280 {
281   if (INTP (obj))
282     {
283       int num = XINT (obj);
284
285       return (BT_UINT16_MIN <= num) && (num <= BT_UINT16_MAX);
286     }
287   else
288     return 0;
289 }
290
291 INLINE_HEADER int
292 UINT16_VALUE_P (Lisp_Object obj)
293 {
294   return EQ (obj, Qunbound)
295     || EQ (obj, Qnil) || EQ (obj, Qt) || INT_UINT16_P (obj);
296 }
297
298 INLINE_HEADER unsigned short
299 UINT16_ENCODE (Lisp_Object obj)
300 {
301   if (EQ (obj, Qunbound))
302     return BT_UINT16_unbound;
303   else if (EQ (obj, Qnil))
304     return BT_UINT16_nil;
305   else if (EQ (obj, Qt))
306     return BT_UINT16_t;
307   else
308     return XINT (obj);
309 }
310
311 INLINE_HEADER Lisp_Object
312 UINT16_DECODE (unsigned short n)
313 {
314   if (n == BT_UINT16_unbound)
315     return Qunbound;
316   else if (n == BT_UINT16_nil)
317     return Qnil;
318   else if (n == BT_UINT16_t)
319     return Qt;
320   else
321     return make_int (n);
322 }
323
324 INLINE_HEADER unsigned short
325 UINT8_TO_UINT16 (unsigned char n)
326 {
327   if (n == BT_UINT8_unbound)
328     return BT_UINT16_unbound;
329   else if (n == BT_UINT8_nil)
330     return BT_UINT16_nil;
331   else if (n == BT_UINT8_t)
332     return BT_UINT16_t;
333   else
334     return n;
335 }
336
337 static Lisp_Object
338 mark_uint16_byte_table (Lisp_Object obj)
339 {
340   return Qnil;
341 }
342
343 static void
344 print_uint16_byte_table (Lisp_Object obj,
345                          Lisp_Object printcharfun, int escapeflag)
346 {
347   Lisp_Uint16_Byte_Table *bte = XUINT16_BYTE_TABLE (obj);
348   int i;
349   struct gcpro gcpro1, gcpro2;
350   GCPRO2 (obj, printcharfun);
351
352   write_c_string ("\n#<uint16-byte-table", printcharfun);
353   for (i = 0; i < 256; i++)
354     {
355       unsigned short n = bte->property[i];
356       if ( (i & 15) == 0 )
357         write_c_string ("\n  ", printcharfun);
358       write_c_string (" ", printcharfun);
359       if (n == BT_UINT16_unbound)
360         write_c_string ("void", printcharfun);
361       else if (n == BT_UINT16_nil)
362         write_c_string ("nil", printcharfun);
363       else if (n == BT_UINT16_t)
364         write_c_string ("t", printcharfun);
365       else
366         {
367           char buf[7];
368
369           sprintf (buf, "%hd", n);
370           write_c_string (buf, printcharfun);
371         }
372     }
373   UNGCPRO;
374   write_c_string (">", printcharfun);
375 }
376
377 static int
378 uint16_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
379 {
380   Lisp_Uint16_Byte_Table *te1 = XUINT16_BYTE_TABLE (obj1);
381   Lisp_Uint16_Byte_Table *te2 = XUINT16_BYTE_TABLE (obj2);
382   int i;
383
384   for (i = 0; i < 256; i++)
385     if (te1->property[i] != te2->property[i])
386       return 0;
387   return 1;
388 }
389
390 static unsigned long
391 uint16_byte_table_hash (Lisp_Object obj, int depth)
392 {
393   Lisp_Uint16_Byte_Table *te = XUINT16_BYTE_TABLE (obj);
394   int i;
395   hashcode_t hash = 0;
396
397   for (i = 0; i < 256; i++)
398     hash = HASH2 (hash, te->property[i]);
399   return hash;
400 }
401
402 DEFINE_LRECORD_IMPLEMENTATION ("uint16-byte-table", uint16_byte_table,
403                                mark_uint16_byte_table,
404                                print_uint16_byte_table,
405                                0, uint16_byte_table_equal,
406                                uint16_byte_table_hash,
407                                0 /* uint16_byte_table_description */,
408                                Lisp_Uint16_Byte_Table);
409
410 static Lisp_Object
411 make_uint16_byte_table (unsigned short initval)
412 {
413   Lisp_Object obj;
414   int i;
415   Lisp_Uint16_Byte_Table *cte;
416
417   cte = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
418                              &lrecord_uint16_byte_table);
419
420   for (i = 0; i < 256; i++)
421     cte->property[i] = initval;
422
423   XSETUINT16_BYTE_TABLE (obj, cte);
424   return obj;
425 }
426
427 static Lisp_Object
428 expand_uint8_byte_table_to_uint16 (Lisp_Object table)
429 {
430   Lisp_Object obj;
431   int i;
432   Lisp_Uint8_Byte_Table* bte = XUINT8_BYTE_TABLE(table);
433   Lisp_Uint16_Byte_Table* cte;
434
435   cte = alloc_lcrecord_type (Lisp_Uint16_Byte_Table,
436                              &lrecord_uint16_byte_table);
437   for (i = 0; i < 256; i++)
438     {
439       cte->property[i] = UINT8_TO_UINT16 (bte->property[i]);
440     }
441   XSETUINT16_BYTE_TABLE (obj, cte);
442   return obj;
443 }
444
445 static int
446 uint16_byte_table_same_value_p (Lisp_Object obj)
447 {
448   Lisp_Uint16_Byte_Table *bte = XUINT16_BYTE_TABLE (obj);
449   unsigned short v0 = bte->property[0];
450   int i;
451
452   for (i = 1; i < 256; i++)
453     {
454       if (bte->property[i] != v0)
455         return 0;
456     }
457   return -1;
458 }
459
460 static int
461 map_over_uint16_byte_table (Lisp_Uint16_Byte_Table *ct, Emchar ofs, int place,
462                             Lisp_Object ccs,
463                             int (*fn) (struct chartab_range *range,
464                                        Lisp_Object val, void *arg),
465                             void *arg)
466 {
467   struct chartab_range rainj;
468   int i, retval;
469   int unit = 1 << (8 * place);
470   Emchar c = ofs;
471   Emchar c1;
472
473   rainj.type = CHARTAB_RANGE_CHAR;
474
475   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
476     {
477       if (ct->property[i] != BT_UINT16_unbound)
478         {
479           c1 = c + unit;
480           for (; c < c1 && retval == 0; c++)
481             {
482               if ( NILP (ccs) || charset_code_point (ccs, c) >= 0 )
483                 {
484                   rainj.ch = c;
485                   retval = (fn) (&rainj, UINT16_DECODE (ct->property[i]),
486                                  arg);
487                 }
488             }
489         }
490       else
491         c += unit;
492     }
493   return retval;
494 }
495
496
497 static Lisp_Object
498 mark_byte_table (Lisp_Object obj)
499 {
500   Lisp_Byte_Table *cte = XBYTE_TABLE (obj);
501   int i;
502
503   for (i = 0; i < 256; i++)
504     {
505       mark_object (cte->property[i]);
506     }
507   return Qnil;
508 }
509
510 static void
511 print_byte_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
512 {
513   Lisp_Byte_Table *bte = XBYTE_TABLE (obj);
514   int i;
515   struct gcpro gcpro1, gcpro2;
516   GCPRO2 (obj, printcharfun);
517
518   write_c_string ("\n#<byte-table", printcharfun);
519   for (i = 0; i < 256; i++)
520     {
521       Lisp_Object elt = bte->property[i];
522       if ( (i & 15) == 0 )
523         write_c_string ("\n  ", printcharfun);
524       write_c_string (" ", printcharfun);
525       if (EQ (elt, Qunbound))
526         write_c_string ("void", printcharfun);
527       else
528         print_internal (elt, printcharfun, escapeflag);
529     }
530   UNGCPRO;
531   write_c_string (">", printcharfun);
532 }
533
534 static int
535 byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
536 {
537   Lisp_Byte_Table *cte1 = XBYTE_TABLE (obj1);
538   Lisp_Byte_Table *cte2 = XBYTE_TABLE (obj2);
539   int i;
540
541   for (i = 0; i < 256; i++)
542     if (BYTE_TABLE_P (cte1->property[i]))
543       {
544         if (BYTE_TABLE_P (cte2->property[i]))
545           {
546             if (!byte_table_equal (cte1->property[i],
547                                    cte2->property[i], depth + 1))
548               return 0;
549           }
550         else
551           return 0;
552       }
553     else
554       if (!internal_equal (cte1->property[i], cte2->property[i], depth + 1))
555         return 0;
556   return 1;
557 }
558
559 static unsigned long
560 byte_table_hash (Lisp_Object obj, int depth)
561 {
562   Lisp_Byte_Table *cte = XBYTE_TABLE (obj);
563
564   return internal_array_hash (cte->property, 256, depth);
565 }
566
567 static const struct lrecord_description byte_table_description[] = {
568   { XD_LISP_OBJECT_ARRAY, offsetof(Lisp_Byte_Table, property), 256 },
569   { XD_END }
570 };
571
572 DEFINE_LRECORD_IMPLEMENTATION ("byte-table", byte_table,
573                                mark_byte_table,
574                                print_byte_table,
575                                0, byte_table_equal,
576                                byte_table_hash,
577                                byte_table_description,
578                                Lisp_Byte_Table);
579
580 static Lisp_Object
581 make_byte_table (Lisp_Object initval)
582 {
583   Lisp_Object obj;
584   int i;
585   Lisp_Byte_Table *cte;
586
587   cte = alloc_lcrecord_type (Lisp_Byte_Table, &lrecord_byte_table);
588
589   for (i = 0; i < 256; i++)
590     cte->property[i] = initval;
591
592   XSETBYTE_TABLE (obj, cte);
593   return obj;
594 }
595
596 static int
597 byte_table_same_value_p (Lisp_Object obj)
598 {
599   Lisp_Byte_Table *bte = XBYTE_TABLE (obj);
600   Lisp_Object v0 = bte->property[0];
601   int i;
602
603   for (i = 1; i < 256; i++)
604     {
605       if (!internal_equal (bte->property[i], v0, 0))
606         return 0;
607     }
608   return -1;
609 }
610
611 static int
612 map_over_byte_table (Lisp_Byte_Table *ct, Emchar ofs, int place,
613                      Lisp_Object ccs,
614                      int (*fn) (struct chartab_range *range,
615                                 Lisp_Object val, void *arg),
616                      void *arg)
617 {
618   int i, retval;
619   Lisp_Object v;
620   int unit = 1 << (8 * place);
621   Emchar c = ofs;
622
623   for (i = 0, retval = 0; i < 256 && retval == 0; i++)
624     {
625       v = ct->property[i];
626       if (UINT8_BYTE_TABLE_P (v))
627         {
628           retval
629             = map_over_uint8_byte_table (XUINT8_BYTE_TABLE(v),
630                                          c, place - 1, ccs, fn, arg);
631           c += unit;
632         }
633       else if (UINT16_BYTE_TABLE_P (v))
634         {
635           retval
636             = map_over_uint16_byte_table (XUINT16_BYTE_TABLE(v),
637                                           c, place - 1, ccs, fn, arg);
638           c += unit;
639         }
640       else if (BYTE_TABLE_P (v))
641         {
642           retval = map_over_byte_table (XBYTE_TABLE(v),
643                                         c, place - 1, ccs, fn, arg);
644           c += unit;
645         }
646       else if (!UNBOUNDP (v))
647         {
648           struct chartab_range rainj;
649           Emchar c1 = c + unit;
650
651           rainj.type = CHARTAB_RANGE_CHAR;
652
653           for (; c < c1 && retval == 0; c++)
654             {
655               if ( NILP (ccs) || charset_code_point (ccs, c) >= 0 )
656                 {
657                   rainj.ch = c;
658                   retval = (fn) (&rainj, v, arg);
659                 }
660             }
661         }
662       else
663         c += unit;
664     }
665   return retval;
666 }
667
668
669 Lisp_Object get_byte_table (Lisp_Object table, unsigned char idx);
670 Lisp_Object put_byte_table (Lisp_Object table, unsigned char idx,
671                             Lisp_Object value);
672
673 Lisp_Object
674 get_byte_table (Lisp_Object table, unsigned char idx)
675 {
676   if (UINT8_BYTE_TABLE_P (table))
677     return UINT8_DECODE (XUINT8_BYTE_TABLE(table)->property[idx]);
678   else if (UINT16_BYTE_TABLE_P (table))
679     return UINT16_DECODE (XUINT16_BYTE_TABLE(table)->property[idx]);
680   else if (BYTE_TABLE_P (table))
681     return XBYTE_TABLE(table)->property[idx];
682   else
683     return table;
684 }
685
686 Lisp_Object
687 put_byte_table (Lisp_Object table, unsigned char idx, Lisp_Object value)
688 {
689   if (UINT8_BYTE_TABLE_P (table))
690     {
691       if (UINT8_VALUE_P (value))
692         {
693           XUINT8_BYTE_TABLE(table)->property[idx] = UINT8_ENCODE (value);
694           if (!UINT8_BYTE_TABLE_P (value) &&
695               !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
696               && uint8_byte_table_same_value_p (table))
697             {
698               return value;
699             }
700         }
701       else if (UINT16_VALUE_P (value))
702         {
703           Lisp_Object new = expand_uint8_byte_table_to_uint16 (table);
704
705           XUINT16_BYTE_TABLE(new)->property[idx] = UINT16_ENCODE (value);
706           return new;
707         }
708       else
709         {
710           Lisp_Object new = make_byte_table (Qnil);
711           int i;
712
713           for (i = 0; i < 256; i++)
714             {
715               XBYTE_TABLE(new)->property[i]
716                 = UINT8_DECODE (XUINT8_BYTE_TABLE(table)->property[i]);
717             }
718           XBYTE_TABLE(new)->property[idx] = value;
719           return new;
720         }
721     }
722   else if (UINT16_BYTE_TABLE_P (table))
723     {
724       if (UINT16_VALUE_P (value))
725         {
726           XUINT16_BYTE_TABLE(table)->property[idx] = UINT16_ENCODE (value);
727           if (!UINT8_BYTE_TABLE_P (value) &&
728               !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
729               && uint16_byte_table_same_value_p (table))
730             {
731               return value;
732             }
733         }
734       else
735         {
736           Lisp_Object new = make_byte_table (Qnil);
737           int i;
738
739           for (i = 0; i < 256; i++)
740             {
741               XBYTE_TABLE(new)->property[i]
742                 = UINT16_DECODE (XUINT16_BYTE_TABLE(table)->property[i]);
743             }
744           XBYTE_TABLE(new)->property[idx] = value;
745           return new;
746         }
747     }
748   else if (BYTE_TABLE_P (table))
749     {
750       XBYTE_TABLE(table)->property[idx] = value;
751       if (!UINT8_BYTE_TABLE_P (value) &&
752           !UINT16_BYTE_TABLE_P (value) && !BYTE_TABLE_P (value)
753           && byte_table_same_value_p (table))
754         {
755           return value;
756         }
757     }
758   else if (!internal_equal (table, value, 0))
759     {
760       if (UINT8_VALUE_P (table) && UINT8_VALUE_P (value))
761         {
762           table = make_uint8_byte_table (UINT8_ENCODE (table));
763           XUINT8_BYTE_TABLE(table)->property[idx] = UINT8_ENCODE (value);
764         }
765       else if (UINT16_VALUE_P (table) && UINT16_VALUE_P (value))
766         {
767           table = make_uint16_byte_table (UINT16_ENCODE (table));
768           XUINT16_BYTE_TABLE(table)->property[idx] = UINT16_ENCODE (value);
769         }
770       else
771         {
772           table = make_byte_table (table);
773           XBYTE_TABLE(table)->property[idx] = value;
774         }
775     }
776   return table;
777 }
778
779 static Lisp_Object
780 mark_char_id_table (Lisp_Object obj)
781 {
782   Lisp_Char_ID_Table *cte = XCHAR_ID_TABLE (obj);
783
784   return cte->table;
785 }
786
787 static void
788 print_char_id_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
789 {
790   Lisp_Object table = XCHAR_ID_TABLE (obj)->table;
791   int i;
792   struct gcpro gcpro1, gcpro2;
793   GCPRO2 (obj, printcharfun);
794
795   write_c_string ("#<char-id-table ", printcharfun);
796   for (i = 0; i < 256; i++)
797     {
798       Lisp_Object elt = get_byte_table (table, i);
799       if (i != 0) write_c_string ("\n  ", printcharfun);
800       if (EQ (elt, Qunbound))
801         write_c_string ("void", printcharfun);
802       else
803         print_internal (elt, printcharfun, escapeflag);
804     }
805   UNGCPRO;
806   write_c_string (">", printcharfun);
807 }
808
809 static int
810 char_id_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
811 {
812   Lisp_Object table1 = XCHAR_ID_TABLE (obj1)->table;
813   Lisp_Object table2 = XCHAR_ID_TABLE (obj2)->table;
814   int i;
815
816   for (i = 0; i < 256; i++)
817     {
818       if (!internal_equal (get_byte_table (table1, i),
819                           get_byte_table (table2, i), 0))
820         return 0;
821     }
822   return -1;
823 }
824
825 static unsigned long
826 char_id_table_hash (Lisp_Object obj, int depth)
827 {
828   Lisp_Char_ID_Table *cte = XCHAR_ID_TABLE (obj);
829
830   return char_id_table_hash (cte->table, depth + 1);
831 }
832
833 static const struct lrecord_description char_id_table_description[] = {
834   { XD_LISP_OBJECT, offsetof(Lisp_Char_ID_Table, table) },
835   { XD_END }
836 };
837
838 DEFINE_LRECORD_IMPLEMENTATION ("char-id-table", char_id_table,
839                                mark_char_id_table,
840                                print_char_id_table,
841                                0, char_id_table_equal,
842                                char_id_table_hash,
843                                char_id_table_description,
844                                Lisp_Char_ID_Table);
845
846 Lisp_Object
847 make_char_id_table (Lisp_Object initval)
848 {
849   Lisp_Object obj;
850   Lisp_Char_ID_Table *cte;
851
852   cte = alloc_lcrecord_type (Lisp_Char_ID_Table, &lrecord_char_id_table);
853
854   cte->table = make_byte_table (initval);
855
856   XSETCHAR_ID_TABLE (obj, cte);
857   return obj;
858 }
859
860
861 Lisp_Object
862 get_char_id_table (Emchar ch, Lisp_Object table)
863 {
864   unsigned int code = ch;
865
866   return
867     get_byte_table
868     (get_byte_table
869      (get_byte_table
870       (get_byte_table
871        (XCHAR_ID_TABLE (table)->table,
872         (unsigned char)(code >> 24)),
873        (unsigned char) (code >> 16)),
874       (unsigned char)  (code >> 8)),
875      (unsigned char)    code);
876 }
877
878 void
879 put_char_id_table (Emchar ch, Lisp_Object value, Lisp_Object table)
880 {
881   unsigned int code = ch;
882   Lisp_Object table1, table2, table3, table4;
883
884   table1 = XCHAR_ID_TABLE (table)->table;
885   table2 = get_byte_table (table1, (unsigned char)(code >> 24));
886   table3 = get_byte_table (table2, (unsigned char)(code >> 16));
887   table4 = get_byte_table (table3, (unsigned char)(code >> 8));
888
889   table4 = put_byte_table (table4, (unsigned char)code,         value);
890   table3 = put_byte_table (table3, (unsigned char)(code >> 8),  table4);
891   table2 = put_byte_table (table2, (unsigned char)(code >> 16), table3);
892   XCHAR_ID_TABLE (table)->table
893     = put_byte_table (table1, (unsigned char)(code >> 24), table2);
894 }
895
896 /* Map FN (with client data ARG) in char table CT.
897    Mapping stops the first time FN returns non-zero, and that value
898    becomes the return value of map_char_id_table(). */
899 int
900 map_char_id_table (Lisp_Char_ID_Table *ct,
901                    struct chartab_range *range,
902                    int (*fn) (struct chartab_range *range,
903                               Lisp_Object val, void *arg),
904                    void *arg);
905 int
906 map_char_id_table (Lisp_Char_ID_Table *ct,
907                    struct chartab_range *range,
908                    int (*fn) (struct chartab_range *range,
909                               Lisp_Object val, void *arg),
910                    void *arg)
911 {
912   Lisp_Object v = ct->table;
913
914   switch (range->type)
915     {
916     case CHARTAB_RANGE_ALL:
917       if (UINT8_BYTE_TABLE_P (v))
918         return map_over_uint8_byte_table (XUINT8_BYTE_TABLE(v), 0, 3,
919                                           Qnil, fn, arg);
920       else if (UINT16_BYTE_TABLE_P (v))
921         return map_over_uint16_byte_table (XUINT16_BYTE_TABLE(v), 0, 3,
922                                            Qnil, fn, arg);
923       else if (BYTE_TABLE_P (v))
924         return map_over_byte_table (XBYTE_TABLE(v), 0, 3, Qnil, fn, arg);
925       else if (!UNBOUNDP (v))
926         {
927           struct chartab_range rainj;
928           int unit = 1 << 24;
929           Emchar c = 0;
930           Emchar c1 = c + unit;
931           int retval;
932
933           rainj.type = CHARTAB_RANGE_CHAR;
934
935           for (retval = 0; c < c1 && retval == 0; c++)
936             {
937               rainj.ch = c;
938               retval = (fn) (&rainj, v, arg);
939             }
940         }
941       return 0;
942     case CHARTAB_RANGE_CHARSET:
943       if (UINT8_BYTE_TABLE_P (v))
944         return map_over_uint8_byte_table (XUINT8_BYTE_TABLE(v), 0, 3,
945                                           range->charset, fn, arg);
946       else if (UINT16_BYTE_TABLE_P (v))
947         return map_over_uint16_byte_table (XUINT16_BYTE_TABLE(v), 0, 3,
948                                            range->charset, fn, arg);
949       else if (BYTE_TABLE_P (v))
950         return map_over_byte_table (XBYTE_TABLE(v), 0, 3,
951                                     range->charset, fn, arg);
952       else if (!UNBOUNDP (v))
953         {
954           struct chartab_range rainj;
955           int unit = 1 << 24;
956           Emchar c = 0;
957           Emchar c1 = c + unit;
958           int retval;
959
960           rainj.type = CHARTAB_RANGE_CHAR;
961
962           for (retval = 0; c < c1 && retval == 0; c++)
963             {
964               if ( charset_code_point (range->charset, c) >= 0 )
965                 {
966                   rainj.ch = c;
967                   retval = (fn) (&rainj, v, arg);
968                 }
969             }
970         }
971       return 0;
972     case CHARTAB_RANGE_ROW:
973       {
974         int cell_min, cell_max, i;
975         int retval;
976         struct chartab_range rainj;
977
978         if (XCHARSET_DIMENSION (range->charset) < 2)
979           signal_simple_error ("Charset in row vector must be multi-byte",
980                                range->charset);
981         else
982           {
983             switch (XCHARSET_CHARS (range->charset))
984               {
985               case 94:
986                 cell_min = 33; cell_max = 126;
987                 break;
988               case 96:
989                 cell_min = 32; cell_max = 127;
990                 break;
991               case 128:
992                 cell_min = 0; cell_max = 127;
993                 break;
994               case 256:
995                 cell_min = 0; cell_max = 255;
996                 break;
997               default:
998                 abort ();
999               }
1000           }
1001         if (XCHARSET_DIMENSION (range->charset) == 2)
1002           check_int_range (range->row, cell_min, cell_max);
1003         else if (XCHARSET_DIMENSION (range->charset) == 3)
1004           {
1005             check_int_range (range->row >> 8  , cell_min, cell_max);
1006             check_int_range (range->row & 0xFF, cell_min, cell_max);
1007           }
1008         else if (XCHARSET_DIMENSION (range->charset) == 4)
1009           {
1010             check_int_range ( range->row >> 16       , cell_min, cell_max);
1011             check_int_range ((range->row >> 8) & 0xFF, cell_min, cell_max);
1012             check_int_range ( range->row       & 0xFF, cell_min, cell_max);
1013           }
1014         else
1015           abort ();
1016
1017         rainj.type = CHARTAB_RANGE_CHAR;
1018         for (retval =0, i = cell_min; i <= cell_max && retval == 0; i++)
1019           {
1020             Emchar ch = DECODE_CHAR (range->charset, (range->row << 8) | i);
1021             Lisp_Object val
1022               = get_byte_table (get_byte_table
1023                                 (get_byte_table
1024                                  (get_byte_table
1025                                   (v,
1026                                    (unsigned char)(ch >> 24)),
1027                                   (unsigned char) (ch >> 16)),
1028                                  (unsigned char)  (ch >> 8)),
1029                                 (unsigned char)    ch);
1030
1031             if (!UNBOUNDP (val))
1032               {
1033                 rainj.ch = ch;
1034                 retval = (fn) (&rainj, val, arg);
1035               }
1036           }
1037         return retval;
1038       }
1039     case CHARTAB_RANGE_CHAR:
1040       {
1041         Emchar ch = range->ch;
1042         Lisp_Object val
1043           = get_byte_table (get_byte_table
1044                             (get_byte_table
1045                              (get_byte_table
1046                               (v,
1047                                (unsigned char)(ch >> 24)),
1048                               (unsigned char) (ch >> 16)),
1049                              (unsigned char)  (ch >> 8)),
1050                             (unsigned char)    ch);
1051         struct chartab_range rainj;
1052
1053         if (!UNBOUNDP (val))
1054           {
1055             rainj.type = CHARTAB_RANGE_CHAR;
1056             rainj.ch = ch;
1057             return (fn) (&rainj, val, arg);
1058           }
1059         else
1060           return 0;
1061       }
1062     default:
1063       abort ();
1064     }
1065   return 0;
1066 }
1067
1068
1069 Lisp_Object Vcharacter_composition_table;
1070 Lisp_Object Vcharacter_variant_table;
1071
1072
1073 Lisp_Object Q_decomposition;
1074 Lisp_Object Qto_ucs;
1075 Lisp_Object Q_ucs;
1076 Lisp_Object Qcompat;
1077 Lisp_Object Qisolated;
1078 Lisp_Object Qinitial;
1079 Lisp_Object Qmedial;
1080 Lisp_Object Qfinal;
1081 Lisp_Object Qvertical;
1082 Lisp_Object QnoBreak;
1083 Lisp_Object Qfraction;
1084 Lisp_Object Qsuper;
1085 Lisp_Object Qsub;
1086 Lisp_Object Qcircle;
1087 Lisp_Object Qsquare;
1088 Lisp_Object Qwide;
1089 Lisp_Object Qnarrow;
1090 Lisp_Object Qsmall;
1091 Lisp_Object Qfont;
1092
1093 Emchar to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg);
1094
1095 Emchar
1096 to_char_id (Lisp_Object v, char* err_msg, Lisp_Object err_arg)
1097 {
1098   if (INTP (v))
1099     return XINT (v);
1100   if (CHARP (v))
1101     return XCHAR (v);
1102   else if (EQ (v, Qcompat))
1103     return -1;
1104   else if (EQ (v, Qisolated))
1105     return -2;
1106   else if (EQ (v, Qinitial))
1107     return -3;
1108   else if (EQ (v, Qmedial))
1109     return -4;
1110   else if (EQ (v, Qfinal))
1111     return -5;
1112   else if (EQ (v, Qvertical))
1113     return -6;
1114   else if (EQ (v, QnoBreak))
1115     return -7;
1116   else if (EQ (v, Qfraction))
1117     return -8;
1118   else if (EQ (v, Qsuper))
1119     return -9;
1120   else if (EQ (v, Qsub))
1121     return -10;
1122   else if (EQ (v, Qcircle))
1123     return -11;
1124   else if (EQ (v, Qsquare))
1125     return -12;
1126   else if (EQ (v, Qwide))
1127     return -13;
1128   else if (EQ (v, Qnarrow))
1129     return -14;
1130   else if (EQ (v, Qsmall))
1131     return -15;
1132   else if (EQ (v, Qfont))
1133     return -16;
1134   else 
1135     signal_simple_error (err_msg, err_arg);
1136 }
1137
1138 DEFUN ("get-composite-char", Fget_composite_char, 1, 1, 0, /*
1139 Return character corresponding with list.
1140 */
1141        (list))
1142 {
1143   Lisp_Object table = Vcharacter_composition_table;
1144   Lisp_Object rest = list;
1145
1146   while (CONSP (rest))
1147     {
1148       Lisp_Object v = Fcar (rest);
1149       Lisp_Object ret;
1150       Emchar c = to_char_id (v, "Invalid value for composition", list);
1151
1152       ret = get_char_id_table (c, table);
1153
1154       rest = Fcdr (rest);
1155       if (NILP (rest))
1156         {
1157           if (!CHAR_ID_TABLE_P (ret))
1158             return ret;
1159           else
1160             return Qt;
1161         }
1162       else if (!CONSP (rest))
1163         break;
1164       else if (CHAR_ID_TABLE_P (ret))
1165         table = ret;
1166       else
1167         signal_simple_error ("Invalid table is found with", list);
1168     }
1169   signal_simple_error ("Invalid value for composition", list);
1170 }
1171
1172 DEFUN ("char-variants", Fchar_variants, 1, 1, 0, /*
1173 Return variants of CHARACTER.
1174 */
1175        (character))
1176 {
1177   CHECK_CHAR (character);
1178   return Fcopy_list (get_char_id_table (XCHAR (character),
1179                                         Vcharacter_variant_table));
1180 }
1181
1182 #endif
1183
1184 \f
1185 /* A char table maps from ranges of characters to values.
1186
1187    Implementing a general data structure that maps from arbitrary
1188    ranges of numbers to values is tricky to do efficiently.  As it
1189    happens, it should suffice (and is usually more convenient, anyway)
1190    when dealing with characters to restrict the sorts of ranges that
1191    can be assigned values, as follows:
1192
1193    1) All characters.
1194    2) All characters in a charset.
1195    3) All characters in a particular row of a charset, where a "row"
1196       means all characters with the same first byte.
1197    4) A particular character in a charset.
1198
1199    We use char tables to generalize the 256-element vectors now
1200    littering the Emacs code.
1201
1202    Possible uses (all should be converted at some point):
1203
1204    1) category tables
1205    2) syntax tables
1206    3) display tables
1207    4) case tables
1208    5) keyboard-translate-table?
1209
1210    We provide an
1211    abstract type to generalize the Emacs vectors and Mule
1212    vectors-of-vectors goo.
1213    */
1214
1215 /************************************************************************/
1216 /*                         Char Table object                            */
1217 /************************************************************************/
1218
1219 #ifdef MULE
1220
1221 static Lisp_Object
1222 mark_char_table_entry (Lisp_Object obj)
1223 {
1224   Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (obj);
1225   int i;
1226
1227   for (i = 0; i < 96; i++)
1228     {
1229       mark_object (cte->level2[i]);
1230     }
1231   return Qnil;
1232 }
1233
1234 static int
1235 char_table_entry_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
1236 {
1237   Lisp_Char_Table_Entry *cte1 = XCHAR_TABLE_ENTRY (obj1);
1238   Lisp_Char_Table_Entry *cte2 = XCHAR_TABLE_ENTRY (obj2);
1239   int i;
1240
1241   for (i = 0; i < 96; i++)
1242     if (!internal_equal (cte1->level2[i], cte2->level2[i], depth + 1))
1243       return 0;
1244
1245   return 1;
1246 }
1247
1248 static unsigned long
1249 char_table_entry_hash (Lisp_Object obj, int depth)
1250 {
1251   Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (obj);
1252
1253   return internal_array_hash (cte->level2, 96, depth);
1254 }
1255
1256 static const struct lrecord_description char_table_entry_description[] = {
1257   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Char_Table_Entry, level2), 96 },
1258   { XD_END }
1259 };
1260
1261 DEFINE_LRECORD_IMPLEMENTATION ("char-table-entry", char_table_entry,
1262                                mark_char_table_entry, internal_object_printer,
1263                                0, char_table_entry_equal,
1264                                char_table_entry_hash,
1265                                char_table_entry_description,
1266                                Lisp_Char_Table_Entry);
1267 #endif /* MULE */
1268
1269 static Lisp_Object
1270 mark_char_table (Lisp_Object obj)
1271 {
1272   Lisp_Char_Table *ct = XCHAR_TABLE (obj);
1273   int i;
1274
1275   for (i = 0; i < NUM_ASCII_CHARS; i++)
1276     mark_object (ct->ascii[i]);
1277 #ifdef MULE
1278   for (i = 0; i < NUM_LEADING_BYTES; i++)
1279     mark_object (ct->level1[i]);
1280 #endif
1281   return ct->mirror_table;
1282 }
1283
1284 /* WARNING: All functions of this nature need to be written extremely
1285    carefully to avoid crashes during GC.  Cf. prune_specifiers()
1286    and prune_weak_hash_tables(). */
1287
1288 void
1289 prune_syntax_tables (void)
1290 {
1291   Lisp_Object rest, prev = Qnil;
1292
1293   for (rest = Vall_syntax_tables;
1294        !NILP (rest);
1295        rest = XCHAR_TABLE (rest)->next_table)
1296     {
1297       if (! marked_p (rest))
1298         {
1299           /* This table is garbage.  Remove it from the list. */
1300           if (NILP (prev))
1301             Vall_syntax_tables = XCHAR_TABLE (rest)->next_table;
1302           else
1303             XCHAR_TABLE (prev)->next_table =
1304               XCHAR_TABLE (rest)->next_table;
1305         }
1306     }
1307 }
1308
1309 static Lisp_Object
1310 char_table_type_to_symbol (enum char_table_type type)
1311 {
1312   switch (type)
1313   {
1314   default: abort();
1315   case CHAR_TABLE_TYPE_GENERIC:  return Qgeneric;
1316   case CHAR_TABLE_TYPE_SYNTAX:   return Qsyntax;
1317   case CHAR_TABLE_TYPE_DISPLAY:  return Qdisplay;
1318   case CHAR_TABLE_TYPE_CHAR:     return Qchar;
1319 #ifdef MULE
1320   case CHAR_TABLE_TYPE_CATEGORY: return Qcategory;
1321 #endif
1322   }
1323 }
1324
1325 static enum char_table_type
1326 symbol_to_char_table_type (Lisp_Object symbol)
1327 {
1328   CHECK_SYMBOL (symbol);
1329
1330   if (EQ (symbol, Qgeneric))  return CHAR_TABLE_TYPE_GENERIC;
1331   if (EQ (symbol, Qsyntax))   return CHAR_TABLE_TYPE_SYNTAX;
1332   if (EQ (symbol, Qdisplay))  return CHAR_TABLE_TYPE_DISPLAY;
1333   if (EQ (symbol, Qchar))     return CHAR_TABLE_TYPE_CHAR;
1334 #ifdef MULE
1335   if (EQ (symbol, Qcategory)) return CHAR_TABLE_TYPE_CATEGORY;
1336 #endif
1337
1338   signal_simple_error ("Unrecognized char table type", symbol);
1339   return CHAR_TABLE_TYPE_GENERIC; /* not reached */
1340 }
1341
1342 static void
1343 print_chartab_range (Emchar first, Emchar last, Lisp_Object val,
1344                      Lisp_Object printcharfun)
1345 {
1346   if (first != last)
1347     {
1348       write_c_string (" (", printcharfun);
1349       print_internal (make_char (first), printcharfun, 0);
1350       write_c_string (" ", printcharfun);
1351       print_internal (make_char (last), printcharfun, 0);
1352       write_c_string (") ", printcharfun);
1353     }
1354   else
1355     {
1356       write_c_string (" ", printcharfun);
1357       print_internal (make_char (first), printcharfun, 0);
1358       write_c_string (" ", printcharfun);
1359     }
1360   print_internal (val, printcharfun, 1);
1361 }
1362
1363 #ifdef MULE
1364
1365 static void
1366 print_chartab_charset_row (Lisp_Object charset,
1367                            int row,
1368                            Lisp_Char_Table_Entry *cte,
1369                            Lisp_Object printcharfun)
1370 {
1371   int i;
1372   Lisp_Object cat = Qunbound;
1373   int first = -1;
1374
1375   for (i = 32; i < 128; i++)
1376     {
1377       Lisp_Object pam = cte->level2[i - 32];
1378
1379       if (first == -1)
1380         {
1381           first = i;
1382           cat = pam;
1383           continue;
1384         }
1385
1386       if (!EQ (cat, pam))
1387         {
1388           if (row == -1)
1389             print_chartab_range (MAKE_CHAR (charset, first, 0),
1390                                  MAKE_CHAR (charset, i - 1, 0),
1391                                  cat, printcharfun);
1392           else
1393             print_chartab_range (MAKE_CHAR (charset, row, first),
1394                                  MAKE_CHAR (charset, row, i - 1),
1395                                  cat, printcharfun);
1396           first = -1;
1397           i--;
1398         }
1399     }
1400
1401   if (first != -1)
1402     {
1403       if (row == -1)
1404         print_chartab_range (MAKE_CHAR (charset, first, 0),
1405                              MAKE_CHAR (charset, i - 1, 0),
1406                              cat, printcharfun);
1407       else
1408         print_chartab_range (MAKE_CHAR (charset, row, first),
1409                              MAKE_CHAR (charset, row, i - 1),
1410                              cat, printcharfun);
1411     }
1412 }
1413
1414 static void
1415 print_chartab_two_byte_charset (Lisp_Object charset,
1416                                 Lisp_Char_Table_Entry *cte,
1417                                 Lisp_Object printcharfun)
1418 {
1419   int i;
1420
1421   for (i = 32; i < 128; i++)
1422     {
1423       Lisp_Object jen = cte->level2[i - 32];
1424
1425       if (!CHAR_TABLE_ENTRYP (jen))
1426         {
1427           char buf[100];
1428
1429           write_c_string (" [", printcharfun);
1430           print_internal (XCHARSET_NAME (charset), printcharfun, 0);
1431           sprintf (buf, " %d] ", i);
1432           write_c_string (buf, printcharfun);
1433           print_internal (jen, printcharfun, 0);
1434         }
1435       else
1436         print_chartab_charset_row (charset, i, XCHAR_TABLE_ENTRY (jen),
1437                                    printcharfun);
1438     }
1439 }
1440
1441 #endif /* MULE */
1442
1443 static void
1444 print_char_table (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
1445 {
1446   Lisp_Char_Table *ct = XCHAR_TABLE (obj);
1447   char buf[200];
1448
1449   sprintf (buf, "#s(char-table type %s data (",
1450            string_data (symbol_name (XSYMBOL
1451                                      (char_table_type_to_symbol (ct->type)))));
1452   write_c_string (buf, printcharfun);
1453
1454   /* Now write out the ASCII/Control-1 stuff. */
1455   {
1456     int i;
1457     int first = -1;
1458     Lisp_Object val = Qunbound;
1459
1460     for (i = 0; i < NUM_ASCII_CHARS; i++)
1461       {
1462         if (first == -1)
1463           {
1464             first = i;
1465             val = ct->ascii[i];
1466             continue;
1467           }
1468
1469         if (!EQ (ct->ascii[i], val))
1470           {
1471             print_chartab_range (first, i - 1, val, printcharfun);
1472             first = -1;
1473             i--;
1474           }
1475       }
1476
1477     if (first != -1)
1478       print_chartab_range (first, i - 1, val, printcharfun);
1479   }
1480
1481 #ifdef MULE
1482   {
1483     Charset_ID i;
1484
1485     for (i = MIN_LEADING_BYTE; i < MIN_LEADING_BYTE + NUM_LEADING_BYTES;
1486          i++)
1487       {
1488         Lisp_Object ann = ct->level1[i - MIN_LEADING_BYTE];
1489         Lisp_Object charset = CHARSET_BY_LEADING_BYTE (i);
1490
1491         if (!CHARSETP (charset) || i == LEADING_BYTE_ASCII
1492             || i == LEADING_BYTE_CONTROL_1)
1493           continue;
1494         if (!CHAR_TABLE_ENTRYP (ann))
1495           {
1496             write_c_string (" ", printcharfun);
1497             print_internal (XCHARSET_NAME (charset),
1498                             printcharfun, 0);
1499             write_c_string (" ", printcharfun);
1500             print_internal (ann, printcharfun, 0);
1501           }
1502         else
1503           {
1504             Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (ann);
1505             if (XCHARSET_DIMENSION (charset) == 1)
1506               print_chartab_charset_row (charset, -1, cte, printcharfun);
1507             else
1508               print_chartab_two_byte_charset (charset, cte, printcharfun);
1509           }
1510       }
1511   }
1512 #endif /* MULE */
1513
1514   write_c_string ("))", printcharfun);
1515 }
1516
1517 static int
1518 char_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
1519 {
1520   Lisp_Char_Table *ct1 = XCHAR_TABLE (obj1);
1521   Lisp_Char_Table *ct2 = XCHAR_TABLE (obj2);
1522   int i;
1523
1524   if (CHAR_TABLE_TYPE (ct1) != CHAR_TABLE_TYPE (ct2))
1525     return 0;
1526
1527   for (i = 0; i < NUM_ASCII_CHARS; i++)
1528     if (!internal_equal (ct1->ascii[i], ct2->ascii[i], depth + 1))
1529       return 0;
1530
1531 #ifdef MULE
1532   for (i = 0; i < NUM_LEADING_BYTES; i++)
1533     if (!internal_equal (ct1->level1[i], ct2->level1[i], depth + 1))
1534       return 0;
1535 #endif /* MULE */
1536
1537   return 1;
1538 }
1539
1540 static unsigned long
1541 char_table_hash (Lisp_Object obj, int depth)
1542 {
1543   Lisp_Char_Table *ct = XCHAR_TABLE (obj);
1544   unsigned long hashval = internal_array_hash (ct->ascii, NUM_ASCII_CHARS,
1545                                                depth);
1546 #ifdef MULE
1547   hashval = HASH2 (hashval,
1548                    internal_array_hash (ct->level1, NUM_LEADING_BYTES, depth));
1549 #endif /* MULE */
1550   return hashval;
1551 }
1552
1553 static const struct lrecord_description char_table_description[] = {
1554   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Char_Table, ascii), NUM_ASCII_CHARS },
1555 #ifdef MULE
1556   { XD_LISP_OBJECT_ARRAY, offsetof (Lisp_Char_Table, level1), NUM_LEADING_BYTES },
1557 #endif
1558   { XD_LISP_OBJECT, offsetof (Lisp_Char_Table, mirror_table) },
1559   { XD_LO_LINK,     offsetof (Lisp_Char_Table, next_table) },
1560   { XD_END }
1561 };
1562
1563 DEFINE_LRECORD_IMPLEMENTATION ("char-table", char_table,
1564                                mark_char_table, print_char_table, 0,
1565                                char_table_equal, char_table_hash,
1566                                char_table_description,
1567                                Lisp_Char_Table);
1568
1569 DEFUN ("char-table-p", Fchar_table_p, 1, 1, 0, /*
1570 Return non-nil if OBJECT is a char table.
1571
1572 A char table is a table that maps characters (or ranges of characters)
1573 to values.  Char tables are specialized for characters, only allowing
1574 particular sorts of ranges to be assigned values.  Although this
1575 loses in generality, it makes for extremely fast (constant-time)
1576 lookups, and thus is feasible for applications that do an extremely
1577 large number of lookups (e.g. scanning a buffer for a character in
1578 a particular syntax, where a lookup in the syntax table must occur
1579 once per character).
1580
1581 When Mule support exists, the types of ranges that can be assigned
1582 values are
1583
1584 -- all characters
1585 -- an entire charset
1586 -- a single row in a two-octet charset
1587 -- a single character
1588
1589 When Mule support is not present, the types of ranges that can be
1590 assigned values are
1591
1592 -- all characters
1593 -- a single character
1594
1595 To create a char table, use `make-char-table'.
1596 To modify a char table, use `put-char-table' or `remove-char-table'.
1597 To retrieve the value for a particular character, use `get-char-table'.
1598 See also `map-char-table', `clear-char-table', `copy-char-table',
1599 `valid-char-table-type-p', `char-table-type-list',
1600 `valid-char-table-value-p', and `check-char-table-value'.
1601 */
1602        (object))
1603 {
1604   return CHAR_TABLEP (object) ? Qt : Qnil;
1605 }
1606
1607 DEFUN ("char-table-type-list", Fchar_table_type_list, 0, 0, 0, /*
1608 Return a list of the recognized char table types.
1609 See `valid-char-table-type-p'.
1610 */
1611        ())
1612 {
1613 #ifdef MULE
1614   return list5 (Qchar, Qcategory, Qdisplay, Qgeneric, Qsyntax);
1615 #else
1616   return list4 (Qchar, Qdisplay, Qgeneric, Qsyntax);
1617 #endif
1618 }
1619
1620 DEFUN ("valid-char-table-type-p", Fvalid_char_table_type_p, 1, 1, 0, /*
1621 Return t if TYPE if a recognized char table type.
1622
1623 Each char table type is used for a different purpose and allows different
1624 sorts of values.  The different char table types are
1625
1626 `category'
1627         Used for category tables, which specify the regexp categories
1628         that a character is in.  The valid values are nil or a
1629         bit vector of 95 elements.  Higher-level Lisp functions are
1630         provided for working with category tables.  Currently categories
1631         and category tables only exist when Mule support is present.
1632 `char'
1633         A generalized char table, for mapping from one character to
1634         another.  Used for case tables, syntax matching tables,
1635         `keyboard-translate-table', etc.  The valid values are characters.
1636 `generic'
1637         An even more generalized char table, for mapping from a
1638         character to anything.
1639 `display'
1640         Used for display tables, which specify how a particular character
1641         is to appear when displayed.  #### Not yet implemented.
1642 `syntax'
1643         Used for syntax tables, which specify the syntax of a particular
1644         character.  Higher-level Lisp functions are provided for
1645         working with syntax tables.  The valid values are integers.
1646
1647 */
1648        (type))
1649 {
1650   return (EQ (type, Qchar)     ||
1651 #ifdef MULE
1652           EQ (type, Qcategory) ||
1653 #endif
1654           EQ (type, Qdisplay)  ||
1655           EQ (type, Qgeneric)  ||
1656           EQ (type, Qsyntax)) ? Qt : Qnil;
1657 }
1658
1659 DEFUN ("char-table-type", Fchar_table_type, 1, 1, 0, /*
1660 Return the type of CHAR-TABLE.
1661 See `valid-char-table-type-p'.
1662 */
1663        (char_table))
1664 {
1665   CHECK_CHAR_TABLE (char_table);
1666   return char_table_type_to_symbol (XCHAR_TABLE (char_table)->type);
1667 }
1668
1669 void
1670 fill_char_table (Lisp_Char_Table *ct, Lisp_Object value)
1671 {
1672   int i;
1673
1674   for (i = 0; i < NUM_ASCII_CHARS; i++)
1675     ct->ascii[i] = value;
1676 #ifdef MULE
1677   for (i = 0; i < NUM_LEADING_BYTES; i++)
1678     ct->level1[i] = value;
1679 #endif /* MULE */
1680
1681   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
1682     update_syntax_table (ct);
1683 }
1684
1685 DEFUN ("reset-char-table", Freset_char_table, 1, 1, 0, /*
1686 Reset CHAR-TABLE to its default state.
1687 */
1688        (char_table))
1689 {
1690   Lisp_Char_Table *ct;
1691
1692   CHECK_CHAR_TABLE (char_table);
1693   ct = XCHAR_TABLE (char_table);
1694
1695   switch (ct->type)
1696     {
1697     case CHAR_TABLE_TYPE_CHAR:
1698       fill_char_table (ct, make_char (0));
1699       break;
1700     case CHAR_TABLE_TYPE_DISPLAY:
1701     case CHAR_TABLE_TYPE_GENERIC:
1702 #ifdef MULE
1703     case CHAR_TABLE_TYPE_CATEGORY:
1704 #endif /* MULE */
1705       fill_char_table (ct, Qnil);
1706       break;
1707
1708     case CHAR_TABLE_TYPE_SYNTAX:
1709       fill_char_table (ct, make_int (Sinherit));
1710       break;
1711
1712     default:
1713       abort ();
1714     }
1715
1716   return Qnil;
1717 }
1718
1719 DEFUN ("make-char-table", Fmake_char_table, 1, 1, 0, /*
1720 Return a new, empty char table of type TYPE.
1721 Currently recognized types are 'char, 'category, 'display, 'generic,
1722 and 'syntax.  See `valid-char-table-type-p'.
1723 */
1724        (type))
1725 {
1726   Lisp_Char_Table *ct;
1727   Lisp_Object obj;
1728   enum char_table_type ty = symbol_to_char_table_type (type);
1729
1730   ct = alloc_lcrecord_type (Lisp_Char_Table, &lrecord_char_table);
1731   ct->type = ty;
1732   if (ty == CHAR_TABLE_TYPE_SYNTAX)
1733     {
1734       ct->mirror_table = Fmake_char_table (Qgeneric);
1735       fill_char_table (XCHAR_TABLE (ct->mirror_table),
1736                        make_int (Spunct));
1737     }
1738   else
1739     ct->mirror_table = Qnil;
1740   ct->next_table = Qnil;
1741   XSETCHAR_TABLE (obj, ct);
1742   if (ty == CHAR_TABLE_TYPE_SYNTAX)
1743     {
1744       ct->next_table = Vall_syntax_tables;
1745       Vall_syntax_tables = obj;
1746     }
1747   Freset_char_table (obj);
1748   return obj;
1749 }
1750
1751 #ifdef MULE
1752
1753 static Lisp_Object
1754 make_char_table_entry (Lisp_Object initval)
1755 {
1756   Lisp_Object obj;
1757   int i;
1758   Lisp_Char_Table_Entry *cte =
1759     alloc_lcrecord_type (Lisp_Char_Table_Entry, &lrecord_char_table_entry);
1760
1761   for (i = 0; i < 96; i++)
1762     cte->level2[i] = initval;
1763
1764   XSETCHAR_TABLE_ENTRY (obj, cte);
1765   return obj;
1766 }
1767
1768 static Lisp_Object
1769 copy_char_table_entry (Lisp_Object entry)
1770 {
1771   Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (entry);
1772   Lisp_Object obj;
1773   int i;
1774   Lisp_Char_Table_Entry *ctenew =
1775     alloc_lcrecord_type (Lisp_Char_Table_Entry, &lrecord_char_table_entry);
1776
1777   for (i = 0; i < 96; i++)
1778     {
1779       Lisp_Object new = cte->level2[i];
1780       if (CHAR_TABLE_ENTRYP (new))
1781         ctenew->level2[i] = copy_char_table_entry (new);
1782       else
1783         ctenew->level2[i] = new;
1784     }
1785
1786   XSETCHAR_TABLE_ENTRY (obj, ctenew);
1787   return obj;
1788 }
1789
1790 #endif /* MULE */
1791
1792 DEFUN ("copy-char-table", Fcopy_char_table, 1, 1, 0, /*
1793 Return a new char table which is a copy of CHAR-TABLE.
1794 It will contain the same values for the same characters and ranges
1795 as CHAR-TABLE.  The values will not themselves be copied.
1796 */
1797        (char_table))
1798 {
1799   Lisp_Char_Table *ct, *ctnew;
1800   Lisp_Object obj;
1801   int i;
1802
1803   CHECK_CHAR_TABLE (char_table);
1804   ct = XCHAR_TABLE (char_table);
1805   ctnew = alloc_lcrecord_type (Lisp_Char_Table, &lrecord_char_table);
1806   ctnew->type = ct->type;
1807
1808   for (i = 0; i < NUM_ASCII_CHARS; i++)
1809     {
1810       Lisp_Object new = ct->ascii[i];
1811 #ifdef MULE
1812       assert (! (CHAR_TABLE_ENTRYP (new)));
1813 #endif /* MULE */
1814       ctnew->ascii[i] = new;
1815     }
1816
1817 #ifdef MULE
1818
1819   for (i = 0; i < NUM_LEADING_BYTES; i++)
1820     {
1821       Lisp_Object new = ct->level1[i];
1822       if (CHAR_TABLE_ENTRYP (new))
1823         ctnew->level1[i] = copy_char_table_entry (new);
1824       else
1825         ctnew->level1[i] = new;
1826     }
1827
1828 #endif /* MULE */
1829
1830   if (CHAR_TABLEP (ct->mirror_table))
1831     ctnew->mirror_table = Fcopy_char_table (ct->mirror_table);
1832   else
1833     ctnew->mirror_table = ct->mirror_table;
1834   ctnew->next_table = Qnil;
1835   XSETCHAR_TABLE (obj, ctnew);
1836   if (ctnew->type == CHAR_TABLE_TYPE_SYNTAX)
1837     {
1838       ctnew->next_table = Vall_syntax_tables;
1839       Vall_syntax_tables = obj;
1840     }
1841   return obj;
1842 }
1843
1844 static void
1845 decode_char_table_range (Lisp_Object range, struct chartab_range *outrange)
1846 {
1847   if (EQ (range, Qt))
1848     outrange->type = CHARTAB_RANGE_ALL;
1849   else if (CHAR_OR_CHAR_INTP (range))
1850     {
1851       outrange->type = CHARTAB_RANGE_CHAR;
1852       outrange->ch = XCHAR_OR_CHAR_INT (range);
1853     }
1854 #ifndef MULE
1855   else
1856     signal_simple_error ("Range must be t or a character", range);
1857 #else /* MULE */
1858   else if (VECTORP (range))
1859     {
1860       Lisp_Vector *vec = XVECTOR (range);
1861       Lisp_Object *elts = vector_data (vec);
1862       if (vector_length (vec) != 2)
1863         signal_simple_error ("Length of charset row vector must be 2",
1864                              range);
1865       outrange->type = CHARTAB_RANGE_ROW;
1866       outrange->charset = Fget_charset (elts[0]);
1867       CHECK_INT (elts[1]);
1868       outrange->row = XINT (elts[1]);
1869       if (XCHARSET_DIMENSION (outrange->charset) >= 2)
1870         {
1871           switch (XCHARSET_CHARS (outrange->charset))
1872             {
1873             case 94:
1874               check_int_range (outrange->row, 33, 126);
1875               break;
1876             case 96:
1877               check_int_range (outrange->row, 32, 127);
1878               break;
1879             default:
1880               abort ();
1881             }
1882         }
1883       else
1884         signal_simple_error ("Charset in row vector must be multi-byte",
1885                              outrange->charset);  
1886     }
1887   else
1888     {
1889       if (!CHARSETP (range) && !SYMBOLP (range))
1890         signal_simple_error
1891           ("Char table range must be t, charset, char, or vector", range);
1892       outrange->type = CHARTAB_RANGE_CHARSET;
1893       outrange->charset = Fget_charset (range);
1894     }
1895 #endif /* MULE */
1896 }
1897
1898 #ifdef MULE
1899
1900 /* called from CHAR_TABLE_VALUE(). */
1901 Lisp_Object
1902 get_non_ascii_char_table_value (Lisp_Char_Table *ct, Charset_ID leading_byte,
1903                                Emchar c)
1904 {
1905   Lisp_Object val;
1906 #ifdef UTF2000
1907   Lisp_Object charset;
1908 #else
1909   Lisp_Object charset = CHARSET_BY_LEADING_BYTE (leading_byte);
1910 #endif
1911   int byte1, byte2;
1912
1913 #ifdef UTF2000
1914   BREAKUP_CHAR (c, charset, byte1, byte2);
1915 #else
1916   BREAKUP_CHAR_1_UNSAFE (c, charset, byte1, byte2);
1917 #endif
1918   val = ct->level1[leading_byte - MIN_LEADING_BYTE];
1919   if (CHAR_TABLE_ENTRYP (val))
1920     {
1921       Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (val);
1922       val = cte->level2[byte1 - 32];
1923       if (CHAR_TABLE_ENTRYP (val))
1924         {
1925           cte = XCHAR_TABLE_ENTRY (val);
1926           assert (byte2 >= 32);
1927           val = cte->level2[byte2 - 32];
1928           assert (!CHAR_TABLE_ENTRYP (val));
1929         }
1930     }
1931
1932   return val;
1933 }
1934
1935 #endif /* MULE */
1936
1937 Lisp_Object
1938 get_char_table (Emchar ch, Lisp_Char_Table *ct)
1939 {
1940 #ifdef MULE
1941   {
1942     Lisp_Object charset;
1943     int byte1, byte2;
1944     Lisp_Object val;
1945
1946     BREAKUP_CHAR (ch, charset, byte1, byte2);
1947
1948     if (EQ (charset, Vcharset_ascii))
1949       val = ct->ascii[byte1];
1950     else if (EQ (charset, Vcharset_control_1))
1951       val = ct->ascii[byte1 + 128];
1952     else
1953       {
1954         int lb = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE;
1955         val = ct->level1[lb];
1956         if (CHAR_TABLE_ENTRYP (val))
1957           {
1958             Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (val);
1959             val = cte->level2[byte1 - 32];
1960             if (CHAR_TABLE_ENTRYP (val))
1961               {
1962                 cte = XCHAR_TABLE_ENTRY (val);
1963                 assert (byte2 >= 32);
1964                 val = cte->level2[byte2 - 32];
1965                 assert (!CHAR_TABLE_ENTRYP (val));
1966               }
1967           }
1968       }
1969
1970     return val;
1971   }
1972 #else /* not MULE */
1973   return ct->ascii[(unsigned char)ch];
1974 #endif /* not MULE */
1975 }
1976
1977
1978 DEFUN ("get-char-table", Fget_char_table, 2, 2, 0, /*
1979 Find value for CHARACTER in CHAR-TABLE.
1980 */
1981        (character, char_table))
1982 {
1983   CHECK_CHAR_TABLE (char_table);
1984   CHECK_CHAR_COERCE_INT (character);
1985
1986   return get_char_table (XCHAR (character), XCHAR_TABLE (char_table));
1987 }
1988
1989 DEFUN ("get-range-char-table", Fget_range_char_table, 2, 3, 0, /*
1990 Find value for a range in CHAR-TABLE.
1991 If there is more than one value, return MULTI (defaults to nil).
1992 */
1993        (range, char_table, multi))
1994 {
1995   Lisp_Char_Table *ct;
1996   struct chartab_range rainj;
1997
1998   if (CHAR_OR_CHAR_INTP (range))
1999     return Fget_char_table (range, char_table);
2000   CHECK_CHAR_TABLE (char_table);
2001   ct = XCHAR_TABLE (char_table);
2002
2003   decode_char_table_range (range, &rainj);
2004   switch (rainj.type)
2005     {
2006     case CHARTAB_RANGE_ALL:
2007       {
2008         int i;
2009         Lisp_Object first = ct->ascii[0];
2010
2011         for (i = 1; i < NUM_ASCII_CHARS; i++)
2012           if (!EQ (first, ct->ascii[i]))
2013             return multi;
2014
2015 #ifdef MULE
2016         for (i = MIN_LEADING_BYTE; i < MIN_LEADING_BYTE + NUM_LEADING_BYTES;
2017              i++)
2018           {
2019             if (!CHARSETP (CHARSET_BY_LEADING_BYTE (i))
2020                 || i == LEADING_BYTE_ASCII
2021                 || i == LEADING_BYTE_CONTROL_1)
2022               continue;
2023             if (!EQ (first, ct->level1[i - MIN_LEADING_BYTE]))
2024               return multi;
2025           }
2026 #endif /* MULE */
2027
2028         return first;
2029       }
2030
2031 #ifdef MULE
2032     case CHARTAB_RANGE_CHARSET:
2033       if (EQ (rainj.charset, Vcharset_ascii))
2034         {
2035           int i;
2036           Lisp_Object first = ct->ascii[0];
2037
2038           for (i = 1; i < 128; i++)
2039             if (!EQ (first, ct->ascii[i]))
2040               return multi;
2041           return first;
2042         }
2043
2044       if (EQ (rainj.charset, Vcharset_control_1))
2045         {
2046           int i;
2047           Lisp_Object first = ct->ascii[128];
2048
2049           for (i = 129; i < 160; i++)
2050             if (!EQ (first, ct->ascii[i]))
2051               return multi;
2052           return first;
2053         }
2054
2055       {
2056         Lisp_Object val = ct->level1[XCHARSET_LEADING_BYTE (rainj.charset) -
2057                                      MIN_LEADING_BYTE];
2058         if (CHAR_TABLE_ENTRYP (val))
2059           return multi;
2060         return val;
2061       }
2062
2063     case CHARTAB_RANGE_ROW:
2064       {
2065         Lisp_Object val = ct->level1[XCHARSET_LEADING_BYTE (rainj.charset) -
2066                                      MIN_LEADING_BYTE];
2067         if (!CHAR_TABLE_ENTRYP (val))
2068           return val;
2069         val = XCHAR_TABLE_ENTRY (val)->level2[rainj.row - 32];
2070         if (CHAR_TABLE_ENTRYP (val))
2071           return multi;
2072         return val;
2073       }
2074 #endif /* not MULE */
2075
2076     default:
2077       abort ();
2078     }
2079
2080   return Qnil; /* not reached */
2081 }
2082
2083 static int
2084 check_valid_char_table_value (Lisp_Object value, enum char_table_type type,
2085                               Error_behavior errb)
2086 {
2087   switch (type)
2088     {
2089     case CHAR_TABLE_TYPE_SYNTAX:
2090       if (!ERRB_EQ (errb, ERROR_ME))
2091         return INTP (value) || (CONSP (value) && INTP (XCAR (value))
2092                                 && CHAR_OR_CHAR_INTP (XCDR (value)));
2093       if (CONSP (value))
2094         {
2095           Lisp_Object cdr = XCDR (value);
2096           CHECK_INT (XCAR (value));
2097           CHECK_CHAR_COERCE_INT (cdr);
2098          }
2099       else
2100         CHECK_INT (value);
2101       break;
2102
2103 #ifdef MULE
2104     case CHAR_TABLE_TYPE_CATEGORY:
2105       if (!ERRB_EQ (errb, ERROR_ME))
2106         return CATEGORY_TABLE_VALUEP (value);
2107       CHECK_CATEGORY_TABLE_VALUE (value);
2108       break;
2109 #endif /* MULE */
2110
2111     case CHAR_TABLE_TYPE_GENERIC:
2112       return 1;
2113
2114     case CHAR_TABLE_TYPE_DISPLAY:
2115       /* #### fix this */
2116       maybe_signal_simple_error ("Display char tables not yet implemented",
2117                                  value, Qchar_table, errb);
2118       return 0;
2119
2120     case CHAR_TABLE_TYPE_CHAR:
2121       if (!ERRB_EQ (errb, ERROR_ME))
2122         return CHAR_OR_CHAR_INTP (value);
2123       CHECK_CHAR_COERCE_INT (value);
2124       break;
2125
2126     default:
2127       abort ();
2128     }
2129
2130   return 0; /* not reached */
2131 }
2132
2133 static Lisp_Object
2134 canonicalize_char_table_value (Lisp_Object value, enum char_table_type type)
2135 {
2136   switch (type)
2137     {
2138     case CHAR_TABLE_TYPE_SYNTAX:
2139       if (CONSP (value))
2140         {
2141           Lisp_Object car = XCAR (value);
2142           Lisp_Object cdr = XCDR (value);
2143           CHECK_CHAR_COERCE_INT (cdr);
2144           return Fcons (car, cdr);
2145         }
2146       break;
2147     case CHAR_TABLE_TYPE_CHAR:
2148       CHECK_CHAR_COERCE_INT (value);
2149       break;
2150     default:
2151       break;
2152     }
2153   return value;
2154 }
2155
2156 DEFUN ("valid-char-table-value-p", Fvalid_char_table_value_p, 2, 2, 0, /*
2157 Return non-nil if VALUE is a valid value for CHAR-TABLE-TYPE.
2158 */
2159        (value, char_table_type))
2160 {
2161   enum char_table_type type = symbol_to_char_table_type (char_table_type);
2162
2163   return check_valid_char_table_value (value, type, ERROR_ME_NOT) ? Qt : Qnil;
2164 }
2165
2166 DEFUN ("check-valid-char-table-value", Fcheck_valid_char_table_value, 2, 2, 0, /*
2167 Signal an error if VALUE is not a valid value for CHAR-TABLE-TYPE.
2168 */
2169        (value, char_table_type))
2170 {
2171   enum char_table_type type = symbol_to_char_table_type (char_table_type);
2172
2173   check_valid_char_table_value (value, type, ERROR_ME);
2174   return Qnil;
2175 }
2176
2177 /* Assign VAL to all characters in RANGE in char table CT. */
2178
2179 void
2180 put_char_table (Lisp_Char_Table *ct, struct chartab_range *range,
2181                 Lisp_Object val)
2182 {
2183   switch (range->type)
2184     {
2185     case CHARTAB_RANGE_ALL:
2186       fill_char_table (ct, val);
2187       return; /* avoid the duplicate call to update_syntax_table() below,
2188                  since fill_char_table() also did that. */
2189
2190 #ifdef MULE
2191     case CHARTAB_RANGE_CHARSET:
2192       if (EQ (range->charset, Vcharset_ascii))
2193         {
2194           int i;
2195           for (i = 0; i < 128; i++)
2196             ct->ascii[i] = val;
2197         }
2198       else if (EQ (range->charset, Vcharset_control_1))
2199         {
2200           int i;
2201           for (i = 128; i < 160; i++)
2202             ct->ascii[i] = val;
2203         }
2204       else
2205         {
2206           int lb = XCHARSET_LEADING_BYTE (range->charset) - MIN_LEADING_BYTE;
2207           ct->level1[lb] = val;
2208         }
2209       break;
2210
2211     case CHARTAB_RANGE_ROW:
2212       {
2213         Lisp_Char_Table_Entry *cte;
2214         int lb = XCHARSET_LEADING_BYTE (range->charset) - MIN_LEADING_BYTE;
2215         /* make sure that there is a separate entry for the row. */
2216         if (!CHAR_TABLE_ENTRYP (ct->level1[lb]))
2217           ct->level1[lb] = make_char_table_entry (ct->level1[lb]);
2218         cte = XCHAR_TABLE_ENTRY (ct->level1[lb]);
2219         cte->level2[range->row - 32] = val;
2220       }
2221       break;
2222 #endif /* MULE */
2223
2224     case CHARTAB_RANGE_CHAR:
2225 #ifdef MULE
2226       {
2227         Lisp_Object charset;
2228         int byte1, byte2;
2229
2230         BREAKUP_CHAR (range->ch, charset, byte1, byte2);
2231         if (EQ (charset, Vcharset_ascii))
2232           ct->ascii[byte1] = val;
2233         else if (EQ (charset, Vcharset_control_1))
2234           ct->ascii[byte1 + 128] = val;
2235         else
2236           {
2237             Lisp_Char_Table_Entry *cte;
2238             int lb = XCHARSET_LEADING_BYTE (charset) - MIN_LEADING_BYTE;
2239             /* make sure that there is a separate entry for the row. */
2240             if (!CHAR_TABLE_ENTRYP (ct->level1[lb]))
2241               ct->level1[lb] = make_char_table_entry (ct->level1[lb]);
2242             cte = XCHAR_TABLE_ENTRY (ct->level1[lb]);
2243             /* now CTE is a char table entry for the charset;
2244                each entry is for a single row (or character of
2245                a one-octet charset). */
2246             if (XCHARSET_DIMENSION (charset) == 1)
2247               cte->level2[byte1 - 32] = val;
2248             else
2249               {
2250                 /* assigning to one character in a two-octet charset. */
2251                 /* make sure that the charset row contains a separate
2252                    entry for each character. */
2253                 if (!CHAR_TABLE_ENTRYP (cte->level2[byte1 - 32]))
2254                   cte->level2[byte1 - 32] =
2255                     make_char_table_entry (cte->level2[byte1 - 32]);
2256                 cte = XCHAR_TABLE_ENTRY (cte->level2[byte1 - 32]);
2257                 cte->level2[byte2 - 32] = val;
2258               }
2259           }
2260       }
2261 #else /* not MULE */
2262       ct->ascii[(unsigned char) (range->ch)] = val;
2263       break;
2264 #endif /* not MULE */
2265     }
2266
2267   if (ct->type == CHAR_TABLE_TYPE_SYNTAX)
2268     update_syntax_table (ct);
2269 }
2270
2271 DEFUN ("put-char-table", Fput_char_table, 3, 3, 0, /*
2272 Set the value for chars in RANGE to be VALUE in CHAR-TABLE.
2273
2274 RANGE specifies one or more characters to be affected and should be
2275 one of the following:
2276
2277 -- t (all characters are affected)
2278 -- A charset (only allowed when Mule support is present)
2279 -- A vector of two elements: a two-octet charset and a row number
2280    (only allowed when Mule support is present)
2281 -- A single character
2282
2283 VALUE must be a value appropriate for the type of CHAR-TABLE.
2284 See `valid-char-table-type-p'.
2285 */
2286        (range, value, char_table))
2287 {
2288   Lisp_Char_Table *ct;
2289   struct chartab_range rainj;
2290
2291   CHECK_CHAR_TABLE (char_table);
2292   ct = XCHAR_TABLE (char_table);
2293   check_valid_char_table_value (value, ct->type, ERROR_ME);
2294   decode_char_table_range (range, &rainj);
2295   value = canonicalize_char_table_value (value, ct->type);
2296   put_char_table (ct, &rainj, value);
2297   return Qnil;
2298 }
2299
2300 /* Map FN over the ASCII chars in CT. */
2301
2302 static int
2303 map_over_charset_ascii (Lisp_Char_Table *ct,
2304                         int (*fn) (struct chartab_range *range,
2305                                    Lisp_Object val, void *arg),
2306                         void *arg)
2307 {
2308   struct chartab_range rainj;
2309   int i, retval;
2310   int start = 0;
2311 #ifdef MULE
2312   int stop = 128;
2313 #else
2314   int stop = 256;
2315 #endif
2316
2317   rainj.type = CHARTAB_RANGE_CHAR;
2318
2319   for (i = start, retval = 0; i < stop && retval == 0; i++)
2320     {
2321       rainj.ch = (Emchar) i;
2322       retval = (fn) (&rainj, ct->ascii[i], arg);
2323     }
2324
2325   return retval;
2326 }
2327
2328 #ifdef MULE
2329
2330 /* Map FN over the Control-1 chars in CT. */
2331
2332 static int
2333 map_over_charset_control_1 (Lisp_Char_Table *ct,
2334                             int (*fn) (struct chartab_range *range,
2335                                        Lisp_Object val, void *arg),
2336                             void *arg)
2337 {
2338   struct chartab_range rainj;
2339   int i, retval;
2340   int start = 128;
2341   int stop  = start + 32;
2342
2343   rainj.type = CHARTAB_RANGE_CHAR;
2344
2345   for (i = start, retval = 0; i < stop && retval == 0; i++)
2346     {
2347       rainj.ch = (Emchar) (i);
2348       retval = (fn) (&rainj, ct->ascii[i], arg);
2349     }
2350
2351   return retval;
2352 }
2353
2354 /* Map FN over the row ROW of two-byte charset CHARSET.
2355    There must be a separate value for that row in the char table.
2356    CTE specifies the char table entry for CHARSET. */
2357
2358 static int
2359 map_over_charset_row (Lisp_Char_Table_Entry *cte,
2360                       Lisp_Object charset, int row,
2361                       int (*fn) (struct chartab_range *range,
2362                                  Lisp_Object val, void *arg),
2363                       void *arg)
2364 {
2365   Lisp_Object val = cte->level2[row - 32];
2366
2367   if (!CHAR_TABLE_ENTRYP (val))
2368     {
2369       struct chartab_range rainj;
2370
2371       rainj.type = CHARTAB_RANGE_ROW;
2372       rainj.charset = charset;
2373       rainj.row = row;
2374       return (fn) (&rainj, val, arg);
2375     }
2376   else
2377     {
2378       struct chartab_range rainj;
2379       int i, retval;
2380       int charset94_p = (XCHARSET_CHARS (charset) == 94);
2381       int start = charset94_p ?  33 :  32;
2382       int stop  = charset94_p ? 127 : 128;
2383
2384       cte = XCHAR_TABLE_ENTRY (val);
2385
2386       rainj.type = CHARTAB_RANGE_CHAR;
2387
2388       for (i = start, retval = 0; i < stop && retval == 0; i++)
2389         {
2390           rainj.ch = MAKE_CHAR (charset, row, i);
2391           retval = (fn) (&rainj, cte->level2[i - 32], arg);
2392         }
2393       return retval;
2394     }
2395 }
2396
2397
2398 static int
2399 map_over_other_charset (Lisp_Char_Table *ct, Charset_ID lb,
2400                         int (*fn) (struct chartab_range *range,
2401                                    Lisp_Object val, void *arg),
2402                         void *arg)
2403 {
2404   Lisp_Object val = ct->level1[lb - MIN_LEADING_BYTE];
2405   Lisp_Object charset = CHARSET_BY_LEADING_BYTE (lb);
2406
2407   if (!CHARSETP (charset)
2408       || lb == LEADING_BYTE_ASCII
2409       || lb == LEADING_BYTE_CONTROL_1)
2410     return 0;
2411
2412   if (!CHAR_TABLE_ENTRYP (val))
2413     {
2414       struct chartab_range rainj;
2415
2416       rainj.type = CHARTAB_RANGE_CHARSET;
2417       rainj.charset = charset;
2418       return (fn) (&rainj, val, arg);
2419     }
2420
2421   {
2422     Lisp_Char_Table_Entry *cte = XCHAR_TABLE_ENTRY (val);
2423     int charset94_p = (XCHARSET_CHARS (charset) == 94);
2424     int start = charset94_p ?  33 :  32;
2425     int stop  = charset94_p ? 127 : 128;
2426     int i, retval;
2427
2428     if (XCHARSET_DIMENSION (charset) == 1)
2429       {
2430         struct chartab_range rainj;
2431         rainj.type = CHARTAB_RANGE_CHAR;
2432
2433         for (i = start, retval = 0; i < stop && retval == 0; i++)
2434           {
2435             rainj.ch = MAKE_CHAR (charset, i, 0);
2436             retval = (fn) (&rainj, cte->level2[i - 32], arg);
2437           }
2438       }
2439     else
2440       {
2441         for (i = start, retval = 0; i < stop && retval == 0; i++)
2442           retval = map_over_charset_row (cte, charset, i, fn, arg);
2443       }
2444
2445     return retval;
2446   }
2447 }
2448
2449 #endif /* MULE */
2450
2451 /* Map FN (with client data ARG) over range RANGE in char table CT.
2452    Mapping stops the first time FN returns non-zero, and that value
2453    becomes the return value of map_char_table(). */
2454
2455 int
2456 map_char_table (Lisp_Char_Table *ct,
2457                 struct chartab_range *range,
2458                 int (*fn) (struct chartab_range *range,
2459                            Lisp_Object val, void *arg),
2460                 void *arg)
2461 {
2462   switch (range->type)
2463     {
2464     case CHARTAB_RANGE_ALL:
2465       {
2466         int retval;
2467
2468         retval = map_over_charset_ascii (ct, fn, arg);
2469         if (retval)
2470           return retval;
2471 #ifdef MULE
2472         retval = map_over_charset_control_1 (ct, fn, arg);
2473         if (retval)
2474           return retval;
2475         {
2476           Charset_ID i;
2477           Charset_ID start = MIN_LEADING_BYTE;
2478           Charset_ID stop  = start + NUM_LEADING_BYTES;
2479
2480           for (i = start, retval = 0; i < stop && retval == 0; i++)
2481             {
2482               retval = map_over_other_charset (ct, i, fn, arg);
2483             }
2484         }
2485 #endif /* MULE */
2486         return retval;
2487       }
2488
2489 #ifdef MULE
2490     case CHARTAB_RANGE_CHARSET:
2491       return map_over_other_charset (ct,
2492                                      XCHARSET_LEADING_BYTE (range->charset),
2493                                      fn, arg);
2494
2495     case CHARTAB_RANGE_ROW:
2496       {
2497         Lisp_Object val = ct->level1[XCHARSET_LEADING_BYTE (range->charset)
2498                                     - MIN_LEADING_BYTE];
2499         if (!CHAR_TABLE_ENTRYP (val))
2500           {
2501             struct chartab_range rainj;
2502
2503             rainj.type = CHARTAB_RANGE_ROW;
2504             rainj.charset = range->charset;
2505             rainj.row = range->row;
2506             return (fn) (&rainj, val, arg);
2507           }
2508         else
2509           return map_over_charset_row (XCHAR_TABLE_ENTRY (val),
2510                                        range->charset, range->row,
2511                                        fn, arg);
2512       }
2513 #endif /* MULE */
2514
2515     case CHARTAB_RANGE_CHAR:
2516       {
2517         Emchar ch = range->ch;
2518         Lisp_Object val = CHAR_TABLE_VALUE_UNSAFE (ct, ch);
2519         struct chartab_range rainj;
2520
2521         rainj.type = CHARTAB_RANGE_CHAR;
2522         rainj.ch = ch;
2523         return (fn) (&rainj, val, arg);
2524       }
2525
2526     default:
2527       abort ();
2528     }
2529
2530   return 0;
2531 }
2532
2533 struct slow_map_char_table_arg
2534 {
2535   Lisp_Object function;
2536   Lisp_Object retval;
2537 };
2538
2539 static int
2540 slow_map_char_table_fun (struct chartab_range *range,
2541                          Lisp_Object val, void *arg)
2542 {
2543   Lisp_Object ranjarg = Qnil;
2544   struct slow_map_char_table_arg *closure =
2545     (struct slow_map_char_table_arg *) arg;
2546
2547   switch (range->type)
2548     {
2549     case CHARTAB_RANGE_ALL:
2550       ranjarg = Qt;
2551       break;
2552
2553 #ifdef MULE
2554     case CHARTAB_RANGE_CHARSET:
2555       ranjarg = XCHARSET_NAME (range->charset);
2556       break;
2557
2558     case CHARTAB_RANGE_ROW:
2559       ranjarg = vector2 (XCHARSET_NAME (range->charset),
2560                          make_int (range->row));
2561       break;
2562 #endif /* MULE */
2563     case CHARTAB_RANGE_CHAR:
2564       ranjarg = make_char (range->ch);
2565       break;
2566     default:
2567       abort ();
2568     }
2569
2570   closure->retval = call2 (closure->function, ranjarg, val);
2571   return !NILP (closure->retval);
2572 }
2573
2574 DEFUN ("map-char-table", Fmap_char_table, 2, 3, 0, /*
2575 Map FUNCTION over entries in CHAR-TABLE, calling it with two args,
2576 each key and value in the table.
2577
2578 RANGE specifies a subrange to map over and is in the same format as
2579 the RANGE argument to `put-range-table'.  If omitted or t, it defaults to
2580 the entire table.
2581 */
2582        (function, char_table, range))
2583 {
2584   Lisp_Char_Table *ct;
2585   struct slow_map_char_table_arg slarg;
2586   struct gcpro gcpro1, gcpro2;
2587   struct chartab_range rainj;
2588
2589   CHECK_CHAR_TABLE (char_table);
2590   ct = XCHAR_TABLE (char_table);
2591   if (NILP (range))
2592     range = Qt;
2593   decode_char_table_range (range, &rainj);
2594   slarg.function = function;
2595   slarg.retval = Qnil;
2596   GCPRO2 (slarg.function, slarg.retval);
2597   map_char_table (ct, &rainj, slow_map_char_table_fun, &slarg);
2598   UNGCPRO;
2599
2600   return slarg.retval;
2601 }
2602
2603 \f
2604 /************************************************************************/
2605 /*                         Character Attributes                         */
2606 /************************************************************************/
2607
2608 #ifdef UTF2000
2609
2610 Lisp_Object Vchar_attribute_hash_table;
2611
2612 /* We store the char-attributes in hash tables with the names as the
2613    key and the actual char-id-table object as the value.  Occasionally
2614    we need to use them in a list format.  These routines provide us
2615    with that. */
2616 struct char_attribute_list_closure
2617 {
2618   Lisp_Object *char_attribute_list;
2619 };
2620
2621 static int
2622 add_char_attribute_to_list_mapper (Lisp_Object key, Lisp_Object value,
2623                                    void *char_attribute_list_closure)
2624 {
2625   /* This function can GC */
2626   struct char_attribute_list_closure *calcl
2627     = (struct char_attribute_list_closure*) char_attribute_list_closure;
2628   Lisp_Object *char_attribute_list = calcl->char_attribute_list;
2629
2630   *char_attribute_list = Fcons (key, *char_attribute_list);
2631   return 0;
2632 }
2633
2634 DEFUN ("char-attribute-list", Fchar_attribute_list, 0, 0, 0, /*
2635 Return the list of all existing character attributes except coded-charsets.
2636 */
2637        ())
2638 {
2639   Lisp_Object char_attribute_list = Qnil;
2640   struct gcpro gcpro1;
2641   struct char_attribute_list_closure char_attribute_list_closure;
2642   
2643   GCPRO1 (char_attribute_list);
2644   char_attribute_list_closure.char_attribute_list = &char_attribute_list;
2645   elisp_maphash (add_char_attribute_to_list_mapper,
2646                  Vchar_attribute_hash_table,
2647                  &char_attribute_list_closure);
2648   UNGCPRO;
2649   return char_attribute_list;
2650 }
2651
2652 DEFUN ("find-char-attribute-table", Ffind_char_attribute_table, 1, 1, 0, /*
2653 Return char-id-table corresponding to ATTRIBUTE.
2654 */
2655        (attribute))
2656 {
2657   return Fgethash (attribute, Vchar_attribute_hash_table, Qnil);
2658 }
2659
2660
2661 /* We store the char-id-tables in hash tables with the attributes as
2662    the key and the actual char-id-table object as the value.  Each
2663    char-id-table stores values of an attribute corresponding with
2664    characters.  Occasionally we need to get attributes of a character
2665    in a association-list format.  These routines provide us with
2666    that. */
2667 struct char_attribute_alist_closure
2668 {
2669   Emchar char_id;
2670   Lisp_Object *char_attribute_alist;
2671 };
2672
2673 static int
2674 add_char_attribute_alist_mapper (Lisp_Object key, Lisp_Object value,
2675                                  void *char_attribute_alist_closure)
2676 {
2677   /* This function can GC */
2678   struct char_attribute_alist_closure *caacl =
2679     (struct char_attribute_alist_closure*) char_attribute_alist_closure;
2680   Lisp_Object ret = get_char_id_table (caacl->char_id, value);
2681   if (!UNBOUNDP (ret))
2682     {
2683       Lisp_Object *char_attribute_alist = caacl->char_attribute_alist;
2684       *char_attribute_alist
2685         = Fcons (Fcons (key, ret), *char_attribute_alist);
2686     }
2687   return 0;
2688 }
2689
2690 DEFUN ("char-attribute-alist", Fchar_attribute_alist, 1, 1, 0, /*
2691 Return the alist of attributes of CHARACTER.
2692 */
2693        (character))
2694 {
2695   Lisp_Object alist = Qnil;
2696   int i;
2697
2698   CHECK_CHAR (character);
2699   {
2700     struct gcpro gcpro1;
2701     struct char_attribute_alist_closure char_attribute_alist_closure;
2702   
2703     GCPRO1 (alist);
2704     char_attribute_alist_closure.char_id = XCHAR (character);
2705     char_attribute_alist_closure.char_attribute_alist = &alist;
2706     elisp_maphash (add_char_attribute_alist_mapper,
2707                    Vchar_attribute_hash_table,
2708                    &char_attribute_alist_closure);
2709     UNGCPRO;
2710   }
2711
2712   for (i = 0; i < countof (chlook->charset_by_leading_byte); i++)
2713     {
2714       Lisp_Object ccs = chlook->charset_by_leading_byte[i];
2715
2716       if (!NILP (ccs))
2717         {
2718           Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
2719           Lisp_Object cpos;
2720
2721           if ( CHAR_ID_TABLE_P (encoding_table)
2722                && INTP (cpos = get_char_id_table (XCHAR (character),
2723                                                   encoding_table)) )
2724             {
2725               alist = Fcons (Fcons (ccs, cpos), alist);
2726             }
2727         }
2728     }
2729   return alist;
2730 }
2731
2732 DEFUN ("get-char-attribute", Fget_char_attribute, 2, 3, 0, /*
2733 Return the value of CHARACTER's ATTRIBUTE.
2734 Return DEFAULT-VALUE if the value is not exist.
2735 */
2736        (character, attribute, default_value))
2737 {
2738   Lisp_Object ccs;
2739
2740   CHECK_CHAR (character);
2741   if (!NILP (ccs = Ffind_charset (attribute)))
2742     {
2743       Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
2744
2745       if (CHAR_ID_TABLE_P (encoding_table))
2746         return get_char_id_table (XCHAR (character), encoding_table);
2747     }
2748   else
2749     {
2750       Lisp_Object table = Fgethash (attribute,
2751                                     Vchar_attribute_hash_table,
2752                                     Qunbound);
2753       if (!UNBOUNDP (table))
2754         {
2755           Lisp_Object ret = get_char_id_table (XCHAR (character), table);
2756           if (!UNBOUNDP (ret))
2757             return ret;
2758         }
2759     }
2760   return default_value;
2761 }
2762
2763 DEFUN ("put-char-attribute", Fput_char_attribute, 3, 3, 0, /*
2764 Store CHARACTER's ATTRIBUTE with VALUE.
2765 */
2766        (character, attribute, value))
2767 {
2768   Lisp_Object ccs;
2769
2770   CHECK_CHAR (character);
2771   ccs = Ffind_charset (attribute);
2772   if (!NILP (ccs))
2773     {
2774       return put_char_ccs_code_point (character, ccs, value);
2775     }
2776   else if (EQ (attribute, Q_decomposition))
2777     {
2778       Lisp_Object seq;
2779
2780       if (!CONSP (value))
2781         signal_simple_error ("Invalid value for ->decomposition",
2782                              value);
2783
2784       if (CONSP (Fcdr (value)))
2785         {
2786           Lisp_Object rest = value;
2787           Lisp_Object table = Vcharacter_composition_table;
2788           size_t len;
2789           int i = 0;
2790
2791           GET_EXTERNAL_LIST_LENGTH (rest, len);
2792           seq = make_vector (len, Qnil);
2793
2794           while (CONSP (rest))
2795             {
2796               Lisp_Object v = Fcar (rest);
2797               Lisp_Object ntable;
2798               Emchar c
2799                 = to_char_id (v, "Invalid value for ->decomposition", value);
2800
2801               if (c < 0)
2802                 XVECTOR_DATA(seq)[i++] = v;
2803               else
2804                 XVECTOR_DATA(seq)[i++] = make_char (c);
2805               rest = Fcdr (rest);
2806               if (!CONSP (rest))
2807                 {
2808                   put_char_id_table (c, character, table);
2809                   break;
2810                 }
2811               else
2812                 {
2813                   ntable = get_char_id_table (c, table);
2814                   if (!CHAR_ID_TABLE_P (ntable))
2815                     {
2816                       ntable = make_char_id_table (Qnil);
2817                       put_char_id_table (c, ntable, table);
2818                     }
2819                   table = ntable;
2820                 }
2821             }
2822         }
2823       else
2824         {
2825           Lisp_Object v = Fcar (value);
2826
2827           if (INTP (v))
2828             {
2829               Emchar c = XINT (v);
2830               Lisp_Object ret
2831                 = get_char_id_table (c, Vcharacter_variant_table);
2832
2833               if (NILP (Fmemq (v, ret)))
2834                 {
2835                   put_char_id_table (c, Fcons (character, ret),
2836                                      Vcharacter_variant_table);
2837                 }
2838             }
2839           seq = make_vector (1, v);
2840         }
2841       value = seq;
2842     }
2843   else if (EQ (attribute, Qto_ucs) || EQ (attribute, Q_ucs))
2844     {
2845       Lisp_Object ret;
2846       Emchar c;
2847
2848       if (!INTP (value))
2849         signal_simple_error ("Invalid value for ->ucs", value);
2850
2851       c = XINT (value);
2852
2853       ret = get_char_id_table (c, Vcharacter_variant_table);
2854       if (NILP (Fmemq (character, ret)))
2855         {
2856           put_char_id_table (c, Fcons (character, ret),
2857                              Vcharacter_variant_table);
2858         }
2859 #if 0
2860       if (EQ (attribute, Q_ucs))
2861         attribute = Qto_ucs;
2862 #endif
2863     }
2864   {
2865     Lisp_Object table = Fgethash (attribute,
2866                                   Vchar_attribute_hash_table,
2867                                   Qnil);
2868
2869     if (NILP (table))
2870       {
2871         table = make_char_id_table (Qunbound);
2872         Fputhash (attribute, table, Vchar_attribute_hash_table);
2873       }
2874     put_char_id_table (XCHAR (character), value, table);
2875     return value;
2876   }
2877 }
2878   
2879 DEFUN ("remove-char-attribute", Fremove_char_attribute, 2, 2, 0, /*
2880 Remove CHARACTER's ATTRIBUTE.
2881 */
2882        (character, attribute))
2883 {
2884   Lisp_Object ccs;
2885
2886   CHECK_CHAR (character);
2887   ccs = Ffind_charset (attribute);
2888   if (!NILP (ccs))
2889     {
2890       return remove_char_ccs (character, ccs);
2891     }
2892   else
2893     {
2894       Lisp_Object table = Fgethash (attribute,
2895                                     Vchar_attribute_hash_table,
2896                                     Qunbound);
2897       if (!UNBOUNDP (table))
2898         {
2899           put_char_id_table (XCHAR (character), Qunbound, table);
2900           return Qt;
2901         }
2902     }
2903   return Qnil;
2904 }
2905
2906 DEFUN ("map-char-attribute", Fmap_char_attribute, 2, 3, 0, /*
2907 Map FUNCTION over entries in ATTRIBUTE, calling it with two args,
2908 each key and value in the table.
2909
2910 RANGE specifies a subrange to map over and is in the same format as
2911 the RANGE argument to `put-range-table'.  If omitted or t, it defaults to
2912 the entire table.
2913 */
2914        (function, attribute, range))
2915 {
2916   Lisp_Object ccs;
2917   Lisp_Char_ID_Table *ct;
2918   struct slow_map_char_table_arg slarg;
2919   struct gcpro gcpro1, gcpro2;
2920   struct chartab_range rainj;
2921
2922   if (!NILP (ccs = Ffind_charset (attribute)))
2923     {
2924       Lisp_Object encoding_table = XCHARSET_ENCODING_TABLE (ccs);
2925
2926       if (CHAR_ID_TABLE_P (encoding_table))
2927         ct = XCHAR_ID_TABLE (encoding_table);
2928       else
2929         return Qnil;
2930     }
2931   else
2932     {
2933       Lisp_Object table = Fgethash (attribute,
2934                                     Vchar_attribute_hash_table,
2935                                     Qunbound);
2936       if (CHAR_ID_TABLE_P (table))
2937         ct = XCHAR_ID_TABLE (table);
2938       else
2939         return Qnil;
2940     }
2941   if (NILP (range))
2942     range = Qt;
2943   decode_char_table_range (range, &rainj);
2944   slarg.function = function;
2945   slarg.retval = Qnil;
2946   GCPRO2 (slarg.function, slarg.retval);
2947   map_char_id_table (ct, &rainj, slow_map_char_table_fun, &slarg);
2948   UNGCPRO;
2949
2950   return slarg.retval;
2951 }
2952
2953 EXFUN (Fmake_char, 3);
2954 EXFUN (Fdecode_char, 2);
2955
2956 DEFUN ("define-char", Fdefine_char, 1, 1, 0, /*
2957 Store character's ATTRIBUTES.
2958 */
2959        (attributes))
2960 {
2961   Lisp_Object rest = attributes;
2962   Lisp_Object code = Fcdr (Fassq (Qucs, attributes));
2963   Lisp_Object character;
2964
2965   if (NILP (code))
2966     {
2967       while (CONSP (rest))
2968         {
2969           Lisp_Object cell = Fcar (rest);
2970           Lisp_Object ccs;
2971
2972           if (!LISTP (cell))
2973             signal_simple_error ("Invalid argument", attributes);
2974           if (!NILP (ccs = Ffind_charset (Fcar (cell)))
2975               && ((XCHARSET_FINAL (ccs) != 0) ||
2976                   (XCHARSET_UCS_MAX (ccs) > 0)) )
2977             {
2978               cell = Fcdr (cell);
2979               if (CONSP (cell))
2980                 character = Fmake_char (ccs, Fcar (cell), Fcar (Fcdr (cell)));
2981               else
2982                 character = Fdecode_char (ccs, cell);
2983               if (!NILP (character))
2984                 goto setup_attributes;
2985             }
2986           rest = Fcdr (rest);
2987         }
2988       if ( (!NILP (code = Fcdr (Fassq (Qto_ucs, attributes)))) ||
2989            (!NILP (code = Fcdr (Fassq (Q_ucs, attributes)))) )
2990         
2991         {
2992           if (!INTP (code))
2993             signal_simple_error ("Invalid argument", attributes);
2994           else
2995             character = make_char (XINT (code) + 0x100000);
2996           goto setup_attributes;
2997         }
2998       return Qnil;
2999     }
3000   else if (!INTP (code))
3001     signal_simple_error ("Invalid argument", attributes);
3002   else
3003     character = make_char (XINT (code));
3004
3005  setup_attributes:
3006   rest = attributes;
3007   while (CONSP (rest))
3008     {
3009       Lisp_Object cell = Fcar (rest);
3010
3011       if (!LISTP (cell))
3012         signal_simple_error ("Invalid argument", attributes);
3013
3014       Fput_char_attribute (character, Fcar (cell), Fcdr (cell));
3015       rest = Fcdr (rest);
3016     }
3017   return character;
3018 }
3019
3020 DEFUN ("find-char", Ffind_char, 1, 1, 0, /*
3021 Retrieve the character of the given ATTRIBUTES.
3022 */
3023        (attributes))
3024 {
3025   Lisp_Object rest = attributes;
3026   Lisp_Object code;
3027
3028   while (CONSP (rest))
3029     {
3030       Lisp_Object cell = Fcar (rest);
3031       Lisp_Object ccs;
3032
3033       if (!LISTP (cell))
3034         signal_simple_error ("Invalid argument", attributes);
3035       if (!NILP (ccs = Ffind_charset (Fcar (cell))))
3036         {
3037           cell = Fcdr (cell);
3038           if (CONSP (cell))
3039             return Fmake_char (ccs, Fcar (cell), Fcar (Fcdr (cell)));
3040           else
3041             return Fdecode_char (ccs, cell);
3042         }
3043       rest = Fcdr (rest);
3044     }
3045   if ( (!NILP (code = Fcdr (Fassq (Qto_ucs, attributes)))) ||
3046        (!NILP (code = Fcdr (Fassq (Q_ucs, attributes)))) )
3047     {
3048       if (!INTP (code))
3049         signal_simple_error ("Invalid argument", attributes);
3050       else
3051         return make_char (XINT (code) + 0x100000);
3052     }
3053   return Qnil;
3054 }
3055
3056 #endif
3057
3058 \f
3059 /************************************************************************/
3060 /*                         Char table read syntax                       */
3061 /************************************************************************/
3062
3063 static int
3064 chartab_type_validate (Lisp_Object keyword, Lisp_Object value,
3065                        Error_behavior errb)
3066 {
3067   /* #### should deal with ERRB */
3068   symbol_to_char_table_type (value);
3069   return 1;
3070 }
3071
3072 static int
3073 chartab_data_validate (Lisp_Object keyword, Lisp_Object value,
3074                        Error_behavior errb)
3075 {
3076   Lisp_Object rest;
3077
3078   /* #### should deal with ERRB */
3079   EXTERNAL_LIST_LOOP (rest, value)
3080     {
3081       Lisp_Object range = XCAR (rest);
3082       struct chartab_range dummy;
3083
3084       rest = XCDR (rest);
3085       if (!CONSP (rest))
3086         signal_simple_error ("Invalid list format", value);
3087       if (CONSP (range))
3088         {
3089           if (!CONSP (XCDR (range))
3090               || !NILP (XCDR (XCDR (range))))
3091             signal_simple_error ("Invalid range format", range);
3092           decode_char_table_range (XCAR (range), &dummy);
3093           decode_char_table_range (XCAR (XCDR (range)), &dummy);
3094         }
3095       else
3096         decode_char_table_range (range, &dummy);
3097     }
3098
3099   return 1;
3100 }
3101
3102 static Lisp_Object
3103 chartab_instantiate (Lisp_Object data)
3104 {
3105   Lisp_Object chartab;
3106   Lisp_Object type = Qgeneric;
3107   Lisp_Object dataval = Qnil;
3108
3109   while (!NILP (data))
3110     {
3111       Lisp_Object keyw = Fcar (data);
3112       Lisp_Object valw;
3113
3114       data = Fcdr (data);
3115       valw = Fcar (data);
3116       data = Fcdr (data);
3117       if (EQ (keyw, Qtype))
3118         type = valw;
3119       else if (EQ (keyw, Qdata))
3120         dataval = valw;
3121     }
3122
3123   chartab = Fmake_char_table (type);
3124
3125   data = dataval;
3126   while (!NILP (data))
3127     {
3128       Lisp_Object range = Fcar (data);
3129       Lisp_Object val = Fcar (Fcdr (data));
3130
3131       data = Fcdr (Fcdr (data));
3132       if (CONSP (range))
3133         {
3134           if (CHAR_OR_CHAR_INTP (XCAR (range)))
3135             {
3136               Emchar first = XCHAR_OR_CHAR_INT (Fcar (range));
3137               Emchar last = XCHAR_OR_CHAR_INT (Fcar (Fcdr (range)));
3138               Emchar i;
3139
3140               for (i = first; i <= last; i++)
3141                  Fput_char_table (make_char (i), val, chartab);
3142             }
3143           else
3144             abort ();
3145         }
3146       else
3147         Fput_char_table (range, val, chartab);
3148     }
3149
3150   return chartab;
3151 }
3152
3153 #ifdef MULE
3154
3155 \f
3156 /************************************************************************/
3157 /*                     Category Tables, specifically                    */
3158 /************************************************************************/
3159
3160 DEFUN ("category-table-p", Fcategory_table_p, 1, 1, 0, /*
3161 Return t if OBJECT is a category table.
3162 A category table is a type of char table used for keeping track of
3163 categories.  Categories are used for classifying characters for use
3164 in regexps -- you can refer to a category rather than having to use
3165 a complicated [] expression (and category lookups are significantly
3166 faster).
3167
3168 There are 95 different categories available, one for each printable
3169 character (including space) in the ASCII charset.  Each category
3170 is designated by one such character, called a "category designator".
3171 They are specified in a regexp using the syntax "\\cX", where X is
3172 a category designator.
3173
3174 A category table specifies, for each character, the categories that
3175 the character is in.  Note that a character can be in more than one
3176 category.  More specifically, a category table maps from a character
3177 to either the value nil (meaning the character is in no categories)
3178 or a 95-element bit vector, specifying for each of the 95 categories
3179 whether the character is in that category.
3180
3181 Special Lisp functions are provided that abstract this, so you do not
3182 have to directly manipulate bit vectors.
3183 */
3184        (object))
3185 {
3186   return (CHAR_TABLEP (object) &&
3187           XCHAR_TABLE_TYPE (object) == CHAR_TABLE_TYPE_CATEGORY) ?
3188     Qt : Qnil;
3189 }
3190
3191 static Lisp_Object
3192 check_category_table (Lisp_Object object, Lisp_Object default_)
3193 {
3194   if (NILP (object))
3195     object = default_;
3196   while (NILP (Fcategory_table_p (object)))
3197     object = wrong_type_argument (Qcategory_table_p, object);
3198   return object;
3199 }
3200
3201 int
3202 check_category_char (Emchar ch, Lisp_Object table,
3203                      unsigned int designator, unsigned int not)
3204 {
3205   REGISTER Lisp_Object temp;
3206   Lisp_Char_Table *ctbl;
3207 #ifdef ERROR_CHECK_TYPECHECK
3208   if (NILP (Fcategory_table_p (table)))
3209     signal_simple_error ("Expected category table", table);
3210 #endif
3211   ctbl = XCHAR_TABLE (table);
3212   temp = get_char_table (ch, ctbl);
3213   if (NILP (temp))
3214     return not;
3215
3216   designator -= ' ';
3217   return bit_vector_bit (XBIT_VECTOR (temp), designator) ? !not : not;
3218 }
3219
3220 DEFUN ("check-category-at", Fcheck_category_at, 2, 4, 0, /*
3221 Return t if category of the character at POSITION includes DESIGNATOR.
3222 Optional third arg BUFFER specifies which buffer to use, and defaults
3223 to the current buffer.
3224 Optional fourth arg CATEGORY-TABLE specifies the category table to
3225 use, and defaults to BUFFER's category table.
3226 */
3227        (position, designator, buffer, category_table))
3228 {
3229   Lisp_Object ctbl;
3230   Emchar ch;
3231   unsigned int des;
3232   struct buffer *buf = decode_buffer (buffer, 0);
3233
3234   CHECK_INT (position);
3235   CHECK_CATEGORY_DESIGNATOR (designator);
3236   des = XCHAR (designator);
3237   ctbl = check_category_table (category_table, Vstandard_category_table);
3238   ch = BUF_FETCH_CHAR (buf, XINT (position));
3239   return check_category_char (ch, ctbl, des, 0) ? Qt : Qnil;
3240 }
3241
3242 DEFUN ("char-in-category-p", Fchar_in_category_p, 2, 3, 0, /*
3243 Return t if category of CHARACTER includes DESIGNATOR, else nil.
3244 Optional third arg CATEGORY-TABLE specifies the category table to use,
3245 and defaults to the standard category table.
3246 */
3247        (character, designator, category_table))
3248 {
3249   Lisp_Object ctbl;
3250   Emchar ch;
3251   unsigned int des;
3252
3253   CHECK_CATEGORY_DESIGNATOR (designator);
3254   des = XCHAR (designator);
3255   CHECK_CHAR (character);
3256   ch = XCHAR (character);
3257   ctbl = check_category_table (category_table, Vstandard_category_table);
3258   return check_category_char (ch, ctbl, des, 0) ? Qt : Qnil;
3259 }
3260
3261 DEFUN ("category-table", Fcategory_table, 0, 1, 0, /*
3262 Return BUFFER's current category table.
3263 BUFFER defaults to the current buffer.
3264 */
3265        (buffer))
3266 {
3267   return decode_buffer (buffer, 0)->category_table;
3268 }
3269
3270 DEFUN ("standard-category-table", Fstandard_category_table, 0, 0, 0, /*
3271 Return the standard category table.
3272 This is the one used for new buffers.
3273 */
3274        ())
3275 {
3276   return Vstandard_category_table;
3277 }
3278
3279 DEFUN ("copy-category-table", Fcopy_category_table, 0, 1, 0, /*
3280 Return a new category table which is a copy of CATEGORY-TABLE.
3281 CATEGORY-TABLE defaults to the standard category table.
3282 */
3283        (category_table))
3284 {
3285   if (NILP (Vstandard_category_table))
3286     return Fmake_char_table (Qcategory);
3287
3288   category_table =
3289     check_category_table (category_table, Vstandard_category_table);
3290   return Fcopy_char_table (category_table);
3291 }
3292
3293 DEFUN ("set-category-table", Fset_category_table, 1, 2, 0, /*
3294 Select CATEGORY-TABLE as the new category table for BUFFER.
3295 BUFFER defaults to the current buffer if omitted.
3296 */
3297        (category_table, buffer))
3298 {
3299   struct buffer *buf = decode_buffer (buffer, 0);
3300   category_table = check_category_table (category_table, Qnil);
3301   buf->category_table = category_table;
3302   /* Indicate that this buffer now has a specified category table.  */
3303   buf->local_var_flags |= XINT (buffer_local_flags.category_table);
3304   return category_table;
3305 }
3306
3307 DEFUN ("category-designator-p", Fcategory_designator_p, 1, 1, 0, /*
3308 Return t if OBJECT is a category designator (a char in the range ' ' to '~').
3309 */
3310        (object))
3311 {
3312   return CATEGORY_DESIGNATORP (object) ? Qt : Qnil;
3313 }
3314
3315 DEFUN ("category-table-value-p", Fcategory_table_value_p, 1, 1, 0, /*
3316 Return t if OBJECT is a category table value.
3317 Valid values are nil or a bit vector of size 95.
3318 */
3319        (object))
3320 {
3321   return CATEGORY_TABLE_VALUEP (object) ? Qt : Qnil;
3322 }
3323
3324
3325 #define CATEGORYP(x) \
3326   (CHARP (x) && XCHAR (x) >= 0x20 && XCHAR (x) <= 0x7E)
3327
3328 #define CATEGORY_SET(c)                                         \
3329   (get_char_table(c, XCHAR_TABLE(current_buffer->category_table)))
3330
3331 /* Return 1 if CATEGORY_SET contains CATEGORY, else return 0.
3332    The faster version of `!NILP (Faref (category_set, category))'.  */
3333 #define CATEGORY_MEMBER(category, category_set)                 \
3334   (bit_vector_bit(XBIT_VECTOR (category_set), category - 32))
3335
3336 /* Return 1 if there is a word boundary between two word-constituent
3337    characters C1 and C2 if they appear in this order, else return 0.
3338    Use the macro WORD_BOUNDARY_P instead of calling this function
3339    directly.  */
3340
3341 int word_boundary_p (Emchar c1, Emchar c2);
3342 int
3343 word_boundary_p (Emchar c1, Emchar c2)
3344 {
3345   Lisp_Object category_set1, category_set2;
3346   Lisp_Object tail;
3347   int default_result;
3348
3349 #if 0
3350   if (COMPOSITE_CHAR_P (c1))
3351     c1 = cmpchar_component (c1, 0, 1);
3352   if (COMPOSITE_CHAR_P (c2))
3353     c2 = cmpchar_component (c2, 0, 1);
3354 #endif
3355
3356   if (EQ (CHAR_CHARSET (c1), CHAR_CHARSET (c2)))
3357     {
3358       tail = Vword_separating_categories;
3359       default_result = 0;
3360     }
3361   else
3362     {
3363       tail = Vword_combining_categories;
3364       default_result = 1;
3365     }
3366
3367   category_set1 = CATEGORY_SET (c1);
3368   if (NILP (category_set1))
3369     return default_result;
3370   category_set2 = CATEGORY_SET (c2);
3371   if (NILP (category_set2))
3372     return default_result;
3373
3374   for (; CONSP (tail); tail = XCONS (tail)->cdr)
3375     {
3376       Lisp_Object elt = XCONS(tail)->car;
3377
3378       if (CONSP (elt)
3379           && CATEGORYP (XCONS (elt)->car)
3380           && CATEGORYP (XCONS (elt)->cdr)
3381           && CATEGORY_MEMBER (XCHAR (XCONS (elt)->car), category_set1)
3382           && CATEGORY_MEMBER (XCHAR (XCONS (elt)->cdr), category_set2))
3383         return !default_result;
3384     }
3385   return default_result;
3386 }
3387 #endif /* MULE */
3388
3389 \f
3390 void
3391 syms_of_chartab (void)
3392 {
3393 #ifdef UTF2000
3394   INIT_LRECORD_IMPLEMENTATION (uint8_byte_table);
3395   INIT_LRECORD_IMPLEMENTATION (uint16_byte_table);
3396   INIT_LRECORD_IMPLEMENTATION (byte_table);
3397   INIT_LRECORD_IMPLEMENTATION (char_id_table);
3398
3399   defsymbol (&Qto_ucs,                  "=>ucs");
3400   defsymbol (&Q_ucs,                    "->ucs");
3401   defsymbol (&Q_decomposition,          "->decomposition");
3402   defsymbol (&Qcompat,                  "compat");
3403   defsymbol (&Qisolated,                "isolated");
3404   defsymbol (&Qinitial,                 "initial");
3405   defsymbol (&Qmedial,                  "medial");
3406   defsymbol (&Qfinal,                   "final");
3407   defsymbol (&Qvertical,                "vertical");
3408   defsymbol (&QnoBreak,                 "noBreak");
3409   defsymbol (&Qfraction,                "fraction");
3410   defsymbol (&Qsuper,                   "super");
3411   defsymbol (&Qsub,                     "sub");
3412   defsymbol (&Qcircle,                  "circle");
3413   defsymbol (&Qsquare,                  "square");
3414   defsymbol (&Qwide,                    "wide");
3415   defsymbol (&Qnarrow,                  "narrow");
3416   defsymbol (&Qsmall,                   "small");
3417   defsymbol (&Qfont,                    "font");
3418
3419   DEFSUBR (Fchar_attribute_list);
3420   DEFSUBR (Ffind_char_attribute_table);
3421   DEFSUBR (Fchar_attribute_alist);
3422   DEFSUBR (Fget_char_attribute);
3423   DEFSUBR (Fput_char_attribute);
3424   DEFSUBR (Fremove_char_attribute);
3425   DEFSUBR (Fmap_char_attribute);
3426   DEFSUBR (Fdefine_char);
3427   DEFSUBR (Ffind_char);
3428   DEFSUBR (Fchar_variants);
3429
3430   DEFSUBR (Fget_composite_char);
3431 #endif
3432
3433   INIT_LRECORD_IMPLEMENTATION (char_table);
3434
3435 #ifdef MULE
3436   INIT_LRECORD_IMPLEMENTATION (char_table_entry);
3437
3438   defsymbol (&Qcategory_table_p, "category-table-p");
3439   defsymbol (&Qcategory_designator_p, "category-designator-p");
3440   defsymbol (&Qcategory_table_value_p, "category-table-value-p");
3441 #endif /* MULE */
3442
3443   defsymbol (&Qchar_table, "char-table");
3444   defsymbol (&Qchar_tablep, "char-table-p");
3445
3446   DEFSUBR (Fchar_table_p);
3447   DEFSUBR (Fchar_table_type_list);
3448   DEFSUBR (Fvalid_char_table_type_p);
3449   DEFSUBR (Fchar_table_type);
3450   DEFSUBR (Freset_char_table);
3451   DEFSUBR (Fmake_char_table);
3452   DEFSUBR (Fcopy_char_table);
3453   DEFSUBR (Fget_char_table);
3454   DEFSUBR (Fget_range_char_table);
3455   DEFSUBR (Fvalid_char_table_value_p);
3456   DEFSUBR (Fcheck_valid_char_table_value);
3457   DEFSUBR (Fput_char_table);
3458   DEFSUBR (Fmap_char_table);
3459
3460 #ifdef MULE
3461   DEFSUBR (Fcategory_table_p);
3462   DEFSUBR (Fcategory_table);
3463   DEFSUBR (Fstandard_category_table);
3464   DEFSUBR (Fcopy_category_table);
3465   DEFSUBR (Fset_category_table);
3466   DEFSUBR (Fcheck_category_at);
3467   DEFSUBR (Fchar_in_category_p);
3468   DEFSUBR (Fcategory_designator_p);
3469   DEFSUBR (Fcategory_table_value_p);
3470 #endif /* MULE */
3471
3472 }
3473
3474 void
3475 vars_of_chartab (void)
3476 {
3477 #ifdef UTF2000
3478   Vutf_2000_version = build_string("0.17 (Hōryūji)");
3479   DEFVAR_LISP ("utf-2000-version", &Vutf_2000_version /*
3480 Version number of XEmacs UTF-2000.
3481 */ );
3482
3483   staticpro (&Vcharacter_composition_table);
3484   Vcharacter_composition_table = make_char_id_table (Qnil);
3485
3486   staticpro (&Vcharacter_variant_table);
3487   Vcharacter_variant_table = make_char_id_table (Qnil);
3488 #endif
3489   /* DO NOT staticpro this.  It works just like Vweak_hash_tables. */
3490   Vall_syntax_tables = Qnil;
3491   dump_add_weak_object_chain (&Vall_syntax_tables);
3492 }
3493
3494 void
3495 structure_type_create_chartab (void)
3496 {
3497   struct structure_type *st;
3498
3499   st = define_structure_type (Qchar_table, 0, chartab_instantiate);
3500
3501   define_structure_type_keyword (st, Qtype, chartab_type_validate);
3502   define_structure_type_keyword (st, Qdata, chartab_data_validate);
3503 }
3504
3505 void
3506 complex_vars_of_chartab (void)
3507 {
3508 #ifdef UTF2000
3509   staticpro (&Vchar_attribute_hash_table);
3510   Vchar_attribute_hash_table
3511     = make_lisp_hash_table (16, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
3512 #endif /* UTF2000 */
3513 #ifdef MULE
3514   /* Set this now, so first buffer creation can refer to it. */
3515   /* Make it nil before calling copy-category-table
3516      so that copy-category-table will know not to try to copy from garbage */
3517   Vstandard_category_table = Qnil;
3518   Vstandard_category_table = Fcopy_category_table (Qnil);
3519   staticpro (&Vstandard_category_table);
3520
3521   DEFVAR_LISP ("word-combining-categories", &Vword_combining_categories /*
3522 List of pair (cons) of categories to determine word boundary.
3523
3524 Emacs treats a sequence of word constituent characters as a single
3525 word (i.e. finds no word boundary between them) iff they belongs to
3526 the same charset.  But, exceptions are allowed in the following cases.
3527
3528 \(1) The case that characters are in different charsets is controlled
3529 by the variable `word-combining-categories'.
3530
3531 Emacs finds no word boundary between characters of different charsets
3532 if they have categories matching some element of this list.
3533
3534 More precisely, if an element of this list is a cons of category CAT1
3535 and CAT2, and a multibyte character C1 which has CAT1 is followed by
3536 C2 which has CAT2, there's no word boundary between C1 and C2.
3537
3538 For instance, to tell that ASCII characters and Latin-1 characters can
3539 form a single word, the element `(?l . ?l)' should be in this list
3540 because both characters have the category `l' (Latin characters).
3541
3542 \(2) The case that character are in the same charset is controlled by
3543 the variable `word-separating-categories'.
3544
3545 Emacs find a word boundary between characters of the same charset
3546 if they have categories matching some element of this list.
3547
3548 More precisely, if an element of this list is a cons of category CAT1
3549 and CAT2, and a multibyte character C1 which has CAT1 is followed by
3550 C2 which has CAT2, there's a word boundary between C1 and C2.
3551
3552 For instance, to tell that there's a word boundary between Japanese
3553 Hiragana and Japanese Kanji (both are in the same charset), the
3554 element `(?H . ?C) should be in this list.
3555 */ );
3556
3557   Vword_combining_categories = Qnil;
3558
3559   DEFVAR_LISP ("word-separating-categories", &Vword_separating_categories /*
3560 List of pair (cons) of categories to determine word boundary.
3561 See the documentation of the variable `word-combining-categories'.
3562 */ );
3563
3564   Vword_separating_categories = Qnil;
3565 #endif /* MULE */
3566 }