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