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