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