(charset_get_byte1): Deleted.
[chise/xemacs-chise.git-] / src / mule-charset.c
1 /* Functions to handle multilingual characters.
2    Copyright (C) 1992, 1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: FSF 20.3.  Not in FSF. */
23
24 /* Rewritten by Ben Wing <ben@xemacs.org>. */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "buffer.h"
30 #include "chartab.h"
31 #include "elhash.h"
32 #include "lstream.h"
33 #include "device.h"
34 #include "faces.h"
35 #include "mule-ccl.h"
36
37 /* The various pre-defined charsets. */
38
39 Lisp_Object Vcharset_ascii;
40 Lisp_Object Vcharset_control_1;
41 Lisp_Object Vcharset_latin_iso8859_1;
42 Lisp_Object Vcharset_latin_iso8859_2;
43 Lisp_Object Vcharset_latin_iso8859_3;
44 Lisp_Object Vcharset_latin_iso8859_4;
45 Lisp_Object Vcharset_thai_tis620;
46 Lisp_Object Vcharset_greek_iso8859_7;
47 Lisp_Object Vcharset_arabic_iso8859_6;
48 Lisp_Object Vcharset_hebrew_iso8859_8;
49 Lisp_Object Vcharset_katakana_jisx0201;
50 Lisp_Object Vcharset_latin_jisx0201;
51 Lisp_Object Vcharset_cyrillic_iso8859_5;
52 Lisp_Object Vcharset_latin_iso8859_9;
53 Lisp_Object Vcharset_japanese_jisx0208_1978;
54 Lisp_Object Vcharset_chinese_gb2312;
55 Lisp_Object Vcharset_japanese_jisx0208;
56 Lisp_Object Vcharset_korean_ksc5601;
57 Lisp_Object Vcharset_japanese_jisx0212;
58 Lisp_Object Vcharset_chinese_cns11643_1;
59 Lisp_Object Vcharset_chinese_cns11643_2;
60 #ifdef UTF2000
61 Lisp_Object Vcharset_ucs_bmp;
62 Lisp_Object Vcharset_latin_viscii;
63 Lisp_Object Vcharset_latin_viscii_lower;
64 Lisp_Object Vcharset_latin_viscii_upper;
65 Lisp_Object Vcharset_hiragana_jisx0208;
66 Lisp_Object Vcharset_katakana_jisx0208;
67 #endif
68 Lisp_Object Vcharset_chinese_big5_1;
69 Lisp_Object Vcharset_chinese_big5_2;
70
71 #ifdef ENABLE_COMPOSITE_CHARS
72 Lisp_Object Vcharset_composite;
73
74 /* Hash tables for composite chars.  One maps string representing
75    composed chars to their equivalent chars; one goes the
76    other way. */
77 Lisp_Object Vcomposite_char_char2string_hash_table;
78 Lisp_Object Vcomposite_char_string2char_hash_table;
79
80 static int composite_char_row_next;
81 static int composite_char_col_next;
82
83 #endif /* ENABLE_COMPOSITE_CHARS */
84
85 /* Table of charsets indexed by leading byte. */
86 Lisp_Object charset_by_leading_byte[NUM_LEADING_BYTES];
87
88 /* Table of charsets indexed by type/final-byte/direction. */
89 #ifdef UTF2000
90 Lisp_Object charset_by_attributes[4][128];
91 #else
92 Lisp_Object charset_by_attributes[4][128][2];
93 #endif
94
95 #ifndef UTF2000
96 /* Table of number of bytes in the string representation of a character
97    indexed by the first byte of that representation.
98
99    rep_bytes_by_first_byte(c) is more efficient than the equivalent
100    canonical computation:
101
102    (BYTE_ASCII_P (c) ? 1 : XCHARSET_REP_BYTES (CHARSET_BY_LEADING_BYTE (c))) */
103
104 Bytecount rep_bytes_by_first_byte[0xA0] =
105 { /* 0x00 - 0x7f are for straight ASCII */
106   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
107   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
108   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
109   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
110   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
111   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
112   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
113   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
114   /* 0x80 - 0x8f are for Dimension-1 official charsets */
115 #ifdef CHAR_IS_UCS4
116   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
117 #else
118   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
119 #endif
120   /* 0x90 - 0x9d are for Dimension-2 official charsets */
121   /* 0x9e is for Dimension-1 private charsets */
122   /* 0x9f is for Dimension-2 private charsets */
123   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4
124 };
125 #endif
126
127 #ifdef UTF2000
128 static Lisp_Object
129 mark_char_byte_table (Lisp_Object obj, void (*markobj) (Lisp_Object))
130 {
131   struct Lisp_Char_Byte_Table *cte = XCHAR_BYTE_TABLE (obj);
132   int i;
133
134   for (i = 0; i < 256; i++)
135     {
136       markobj (cte->property[i]);
137     }
138   return Qnil;
139 }
140
141 static int
142 char_byte_table_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
143 {
144   struct Lisp_Char_Byte_Table *cte1 = XCHAR_BYTE_TABLE (obj1);
145   struct Lisp_Char_Byte_Table *cte2 = XCHAR_BYTE_TABLE (obj2);
146   int i;
147
148   for (i = 0; i < 256; i++)
149     if (CHAR_BYTE_TABLE_P (cte1->property[i]))
150       {
151         if (CHAR_BYTE_TABLE_P (cte2->property[i]))
152           {
153             if (!char_byte_table_equal (cte1->property[i],
154                                         cte2->property[i], depth + 1))
155               return 0;
156           }
157         else
158           return 0;
159       }
160     else
161       if (!internal_equal (cte1->property[i], cte2->property[i], depth + 1))
162         return 0;
163   return 1;
164 }
165
166 static unsigned long
167 char_byte_table_hash (Lisp_Object obj, int depth)
168 {
169   struct Lisp_Char_Byte_Table *cte = XCHAR_BYTE_TABLE (obj);
170
171   return internal_array_hash (cte->property, 256, depth);
172 }
173
174 static const struct lrecord_description char_byte_table_description[] = {
175   { XD_LISP_OBJECT, offsetof(struct Lisp_Char_Byte_Table, property), 256 },
176   { XD_END }
177 };
178
179 DEFINE_LRECORD_IMPLEMENTATION ("char-code-table", char_byte_table,
180                                mark_char_byte_table,
181                                internal_object_printer,
182                                0, char_byte_table_equal,
183                                char_byte_table_hash,
184                                char_byte_table_description,
185                                struct Lisp_Char_Byte_Table);
186
187
188 static Lisp_Object
189 make_char_byte_table (Lisp_Object initval)
190 {
191   Lisp_Object obj;
192   int i;
193   struct Lisp_Char_Byte_Table *cte =
194     alloc_lcrecord_type (struct Lisp_Char_Byte_Table,
195                          &lrecord_char_byte_table);
196
197   for (i = 0; i < 256; i++)
198     cte->property[i] = initval;
199
200   XSETCHAR_BYTE_TABLE (obj, cte);
201   return obj;
202 }
203
204 static Lisp_Object
205 copy_char_byte_table (Lisp_Object entry)
206 {
207   struct Lisp_Char_Byte_Table *cte = XCHAR_BYTE_TABLE (entry);
208   Lisp_Object obj;
209   int i;
210   struct Lisp_Char_Byte_Table *ctenew =
211     alloc_lcrecord_type (struct Lisp_Char_Byte_Table,
212                          &lrecord_char_byte_table);
213
214   for (i = 0; i < 256; i++)
215     {
216       Lisp_Object new = cte->property[i];
217       if (CHAR_BYTE_TABLE_P (new))
218         ctenew->property[i] = copy_char_byte_table (new);
219       else
220         ctenew->property[i] = new;
221     }
222
223   XSETCHAR_BYTE_TABLE (obj, ctenew);
224   return obj;
225 }
226
227 #define make_char_code_table(initval) make_char_byte_table(initval)
228
229 Lisp_Object
230 get_char_code_table (Emchar ch, Lisp_Object table)
231 {
232   struct Lisp_Char_Byte_Table* cpt = XCHAR_BYTE_TABLE (table);
233   Lisp_Object ret = cpt->property [ch >> 24];
234
235   if (CHAR_BYTE_TABLE_P (ret))
236     cpt = XCHAR_BYTE_TABLE (ret);
237   else
238     return ret;
239
240   ret = cpt->property [(unsigned char) (ch >> 16)];
241   if (CHAR_BYTE_TABLE_P (ret))
242     cpt = XCHAR_BYTE_TABLE (ret);
243   else
244     return ret;
245
246   ret = cpt->property [(unsigned char) (ch >> 8)];
247   if (CHAR_BYTE_TABLE_P (ret))
248     cpt = XCHAR_BYTE_TABLE (ret);
249   else
250     return ret;
251   
252   return cpt->property [(unsigned char) ch];
253 }
254
255 void
256 put_char_code_table (Emchar ch, Lisp_Object value, Lisp_Object table)
257 {
258   struct Lisp_Char_Byte_Table* cpt1 = XCHAR_BYTE_TABLE (table);
259   Lisp_Object ret = cpt1->property[ch >> 24];
260
261   if (CHAR_BYTE_TABLE_P (ret))
262     {
263       struct Lisp_Char_Byte_Table* cpt2 = XCHAR_BYTE_TABLE (ret);
264       
265       ret = cpt2->property[(unsigned char)(ch >> 16)];
266       if (CHAR_BYTE_TABLE_P (ret))
267         {
268           struct Lisp_Char_Byte_Table* cpt3 = XCHAR_BYTE_TABLE (ret);
269           
270           ret = cpt3->property[(unsigned char)(ch >> 8)];
271           if (CHAR_BYTE_TABLE_P (ret))
272             {
273               struct Lisp_Char_Byte_Table* cpt4
274                 = XCHAR_BYTE_TABLE (ret);
275               
276               cpt4->property[(unsigned char)ch] = value;
277             }
278           else if (!EQ (ret, value))
279             {
280               Lisp_Object cpt4 = make_char_byte_table (ret);
281               
282               XCHAR_BYTE_TABLE(cpt4)->property[(unsigned char)ch] = value;
283               cpt3->property[(unsigned char)(ch >> 8)] = cpt4;
284             }
285         }
286       else if (!EQ (ret, value))
287         {
288           Lisp_Object cpt3 = make_char_byte_table (ret);
289           Lisp_Object cpt4 = make_char_byte_table (ret);
290           
291           XCHAR_BYTE_TABLE(cpt4)->property[(unsigned char)ch] = value;
292           XCHAR_BYTE_TABLE(cpt3)->property[(unsigned char)(ch >> 8)]
293             = cpt4;
294           cpt2->property[(unsigned char)(ch >> 16)] = cpt3;
295         }
296     }
297   else if (!EQ (ret, value))
298     {
299       Lisp_Object cpt2 = make_char_byte_table (ret);
300       Lisp_Object cpt3 = make_char_byte_table (ret);
301       Lisp_Object cpt4 = make_char_byte_table (ret);
302       
303       XCHAR_BYTE_TABLE(cpt4)->property[(unsigned char)ch] = value;
304       XCHAR_BYTE_TABLE(cpt3)->property[(unsigned char)(ch >>  8)] = cpt4;
305       XCHAR_BYTE_TABLE(cpt2)->property[(unsigned char)(ch >> 16)] = cpt3;
306       cpt1->property[(unsigned char)(ch >> 24)] = cpt2;
307     }
308 }
309
310
311 Lisp_Object Vcharacter_attribute_table;
312
313 DEFUN ("char-attribute-alist", Fchar_attribute_alist, 1, 1, 0, /*
314 Return the alist of attributes of CHARACTER.
315 */
316        (character))
317 {
318   return get_char_code_table (XCHAR (character), Vcharacter_attribute_table);
319 }
320
321 DEFUN ("get-char-attribute", Fget_char_attribute, 2, 2, 0, /*
322 Return the value of CHARACTER's ATTRIBUTE.
323 */
324        (character, attribute))
325 {
326   Lisp_Object ret
327     = get_char_code_table (XCHAR (character), Vcharacter_attribute_table);
328
329   if (EQ (ret, Qnil))
330     return Qnil;
331   
332   return Fcdr (Fassq (attribute, ret));
333 }
334
335 DEFUN ("put-char-attribute", Fput_char_attribute, 3, 3, 0, /*
336 Store CHARACTER's ATTRIBUTE with VALUE.
337 */
338        (character, attribute, value))
339 {
340   Emchar char_code = XCHAR (character);
341   Lisp_Object ret
342     = get_char_code_table (char_code, Vcharacter_attribute_table);
343   Lisp_Object cell = Fassq (attribute, ret);
344
345   if (EQ (cell, Qnil))
346     ret = Fcons (Fcons (attribute, value), ret);
347   else
348     Fsetcdr (cell, value);
349   put_char_code_table (char_code, ret, Vcharacter_attribute_table);
350   return ret;
351 }
352
353
354 Lisp_Object Vutf_2000_version;
355 #endif
356
357 #ifndef UTF2000
358 int leading_code_private_11;
359 #endif
360
361 Lisp_Object Qcharsetp;
362
363 /* Qdoc_string, Qdimension, Qchars defined in general.c */
364 Lisp_Object Qregistry, Qfinal, Qgraphic;
365 Lisp_Object Qdirection;
366 Lisp_Object Qreverse_direction_charset;
367 Lisp_Object Qleading_byte;
368 Lisp_Object Qshort_name, Qlong_name;
369
370 Lisp_Object Qascii,
371   Qcontrol_1,
372   Qlatin_iso8859_1,
373   Qlatin_iso8859_2,
374   Qlatin_iso8859_3,
375   Qlatin_iso8859_4,
376   Qthai_tis620,
377   Qgreek_iso8859_7,
378   Qarabic_iso8859_6,
379   Qhebrew_iso8859_8,
380   Qkatakana_jisx0201,
381   Qlatin_jisx0201,
382   Qcyrillic_iso8859_5,
383   Qlatin_iso8859_9,
384   Qjapanese_jisx0208_1978,
385   Qchinese_gb2312,
386   Qjapanese_jisx0208,
387   Qkorean_ksc5601,
388   Qjapanese_jisx0212,
389   Qchinese_cns11643_1,
390   Qchinese_cns11643_2,
391 #ifdef UTF2000
392   Qucs_bmp,
393   Qlatin_viscii,
394   Qlatin_viscii_lower,
395   Qlatin_viscii_upper,
396   Qvietnamese_viscii_lower,
397   Qvietnamese_viscii_upper,
398   Qhiragana_jisx0208,
399   Qkatakana_jisx0208,
400 #endif
401   Qchinese_big5_1,
402   Qchinese_big5_2,
403   Qcomposite;
404
405 Lisp_Object Ql2r, Qr2l;
406
407 Lisp_Object Vcharset_hash_table;
408
409 #ifdef UTF2000
410 static Charset_ID next_allocated_leading_byte;
411 #else
412 static Charset_ID next_allocated_1_byte_leading_byte;
413 static Charset_ID next_allocated_2_byte_leading_byte;
414 #endif
415
416 /* Composite characters are characters constructed by overstriking two
417    or more regular characters.
418
419    1) The old Mule implementation involves storing composite characters
420       in a buffer as a tag followed by all of the actual characters
421       used to make up the composite character.  I think this is a bad
422       idea; it greatly complicates code that wants to handle strings
423       one character at a time because it has to deal with the possibility
424       of great big ungainly characters.  It's much more reasonable to
425       simply store an index into a table of composite characters.
426
427    2) The current implementation only allows for 16,384 separate
428       composite characters over the lifetime of the XEmacs process.
429       This could become a potential problem if the user
430       edited lots of different files that use composite characters.
431       Due to FSF bogosity, increasing the number of allowable
432       composite characters under Mule would decrease the number
433       of possible faces that can exist.  Mule already has shrunk
434       this to 2048, and further shrinkage would become uncomfortable.
435       No such problems exist in XEmacs.
436
437       Composite characters could be represented as 0x80 C1 C2 C3,
438       where each C[1-3] is in the range 0xA0 - 0xFF.  This allows
439       for slightly under 2^20 (one million) composite characters
440       over the XEmacs process lifetime, and you only need to
441       increase the size of a Mule character from 19 to 21 bits.
442       Or you could use 0x80 C1 C2 C3 C4, allowing for about
443       85 million (slightly over 2^26) composite characters. */
444
445 \f
446 /************************************************************************/
447 /*                       Basic Emchar functions                         */
448 /************************************************************************/
449
450 /* Convert a non-ASCII Mule character C into a one-character Mule-encoded
451    string in STR.  Returns the number of bytes stored.
452    Do not call this directly.  Use the macro set_charptr_emchar() instead.
453  */
454
455 Bytecount
456 non_ascii_set_charptr_emchar (Bufbyte *str, Emchar c)
457 {
458   Bufbyte *p;
459 #ifndef UTF2000
460   Charset_ID lb;
461   int c1, c2;
462   Lisp_Object charset;
463 #endif
464
465   p = str;
466 #ifdef UTF2000
467   if ( c <= 0x7f )
468     {
469       *p++ = c;
470     }
471   else if ( c <= 0x7ff )
472     {
473       *p++ = (c >> 6) | 0xc0;
474       *p++ = (c & 0x3f) | 0x80;
475     }
476   else if ( c <= 0xffff )
477     {
478       *p++ =  (c >> 12) | 0xe0;
479       *p++ = ((c >>  6) & 0x3f) | 0x80;
480       *p++ =  (c        & 0x3f) | 0x80;
481     }
482   else if ( c <= 0x1fffff )
483     {
484       *p++ =  (c >> 18) | 0xf0;
485       *p++ = ((c >> 12) & 0x3f) | 0x80;
486       *p++ = ((c >>  6) & 0x3f) | 0x80;
487       *p++ =  (c        & 0x3f) | 0x80;
488     }
489   else if ( c <= 0x3ffffff )
490     {
491       *p++ =  (c >> 24) | 0xf8;
492       *p++ = ((c >> 18) & 0x3f) | 0x80;
493       *p++ = ((c >> 12) & 0x3f) | 0x80;
494       *p++ = ((c >>  6) & 0x3f) | 0x80;
495       *p++ =  (c        & 0x3f) | 0x80;
496     }
497   else
498     {
499       *p++ =  (c >> 30) | 0xfc;
500       *p++ = ((c >> 24) & 0x3f) | 0x80;
501       *p++ = ((c >> 18) & 0x3f) | 0x80;
502       *p++ = ((c >> 12) & 0x3f) | 0x80;
503       *p++ = ((c >>  6) & 0x3f) | 0x80;
504       *p++ =  (c        & 0x3f) | 0x80;
505     }
506 #else
507   BREAKUP_CHAR (c, charset, c1, c2);
508   lb = CHAR_LEADING_BYTE (c);
509   if (LEADING_BYTE_PRIVATE_P (lb))
510     *p++ = PRIVATE_LEADING_BYTE_PREFIX (lb);
511   *p++ = lb;
512   if (EQ (charset, Vcharset_control_1))
513     c1 += 0x20;
514   *p++ = c1 | 0x80;
515   if (c2)
516     *p++ = c2 | 0x80;
517 #endif
518   return (p - str);
519 }
520
521 /* Return the first character from a Mule-encoded string in STR,
522    assuming it's non-ASCII.  Do not call this directly.
523    Use the macro charptr_emchar() instead. */
524
525 Emchar
526 non_ascii_charptr_emchar (CONST Bufbyte *str)
527 {
528 #ifdef UTF2000
529   Bufbyte b;
530   Emchar ch;
531   int len;
532
533   b = *str++;
534   if ( b >= 0xfc )
535     {
536       ch = (b & 0x01);
537       len = 5;
538     }
539   else if ( b >= 0xf8 )
540     {
541       ch = b & 0x03;
542       len = 4;
543     }
544   else if ( b >= 0xf0 )
545     {
546       ch = b & 0x07;
547       len = 3;
548     }
549   else if ( b >= 0xe0 )
550     {
551       ch = b & 0x0f;
552       len = 2;
553     }
554   else if ( b >= 0xc0 )
555     {
556       ch = b & 0x1f;
557       len = 1;
558     }
559   else
560     {
561       ch = b;
562       len = 0;
563     }
564   for( ; len > 0; len-- )
565     {
566       b = *str++;
567       ch = ( ch << 6 ) | ( b & 0x3f );
568     }
569   return ch;
570 #else
571   Bufbyte i0 = *str, i1, i2 = 0;
572   Lisp_Object charset;
573
574   if (i0 == LEADING_BYTE_CONTROL_1)
575     return (Emchar) (*++str - 0x20);
576
577   if (LEADING_BYTE_PREFIX_P (i0))
578     i0 = *++str;
579
580   i1 = *++str & 0x7F;
581
582   charset = CHARSET_BY_LEADING_BYTE (i0);
583   if (XCHARSET_DIMENSION (charset) == 2)
584     i2 = *++str & 0x7F;
585
586   return MAKE_CHAR (charset, i1, i2);
587 #endif
588 }
589
590 /* Return whether CH is a valid Emchar, assuming it's non-ASCII.
591    Do not call this directly.  Use the macro valid_char_p() instead. */
592
593 #ifndef UTF2000
594 int
595 non_ascii_valid_char_p (Emchar ch)
596 {
597   int f1, f2, f3;
598
599   /* Must have only lowest 19 bits set */
600   if (ch & ~0x7FFFF)
601     return 0;
602
603   f1 = CHAR_FIELD1 (ch);
604   f2 = CHAR_FIELD2 (ch);
605   f3 = CHAR_FIELD3 (ch);
606
607   if (f1 == 0)
608     {
609       Lisp_Object charset;
610
611       if (f2 < MIN_CHAR_FIELD2_OFFICIAL ||
612           (f2 > MAX_CHAR_FIELD2_OFFICIAL && f2 < MIN_CHAR_FIELD2_PRIVATE) ||
613            f2 > MAX_CHAR_FIELD2_PRIVATE)
614         return 0;
615       if (f3 < 0x20)
616         return 0;
617
618       if (f3 != 0x20 && f3 != 0x7F)
619         return 1;
620
621       /*
622          NOTE: This takes advantage of the fact that
623          FIELD2_TO_OFFICIAL_LEADING_BYTE and
624          FIELD2_TO_PRIVATE_LEADING_BYTE are the same.
625          */
626       charset = CHARSET_BY_LEADING_BYTE (f2 + FIELD2_TO_OFFICIAL_LEADING_BYTE);
627       return (XCHARSET_CHARS (charset) == 96);
628     }
629   else
630     {
631       Lisp_Object charset;
632
633       if (f1 < MIN_CHAR_FIELD1_OFFICIAL ||
634           (f1 > MAX_CHAR_FIELD1_OFFICIAL && f1 < MIN_CHAR_FIELD1_PRIVATE) ||
635           f1 > MAX_CHAR_FIELD1_PRIVATE)
636         return 0;
637       if (f2 < 0x20 || f3 < 0x20)
638         return 0;
639
640 #ifdef ENABLE_COMPOSITE_CHARS
641       if (f1 + FIELD1_TO_OFFICIAL_LEADING_BYTE == LEADING_BYTE_COMPOSITE)
642         {
643           if (UNBOUNDP (Fgethash (make_int (ch),
644                                   Vcomposite_char_char2string_hash_table,
645                                   Qunbound)))
646             return 0;
647           return 1;
648         }
649 #endif /* ENABLE_COMPOSITE_CHARS */
650
651       if (f2 != 0x20 && f2 != 0x7F && f3 != 0x20 && f3 != 0x7F)
652         return 1;
653
654       if (f1 <= MAX_CHAR_FIELD1_OFFICIAL)
655         charset =
656           CHARSET_BY_LEADING_BYTE (f1 + FIELD1_TO_OFFICIAL_LEADING_BYTE);
657       else
658         charset =
659           CHARSET_BY_LEADING_BYTE (f1 + FIELD1_TO_PRIVATE_LEADING_BYTE);
660
661       return (XCHARSET_CHARS (charset) == 96);
662     }
663 }
664 #endif
665
666 \f
667 /************************************************************************/
668 /*                       Basic string functions                         */
669 /************************************************************************/
670
671 /* Copy the character pointed to by PTR into STR, assuming it's
672    non-ASCII.  Do not call this directly.  Use the macro
673    charptr_copy_char() instead. */
674
675 Bytecount
676 non_ascii_charptr_copy_char (CONST Bufbyte *ptr, Bufbyte *str)
677 {
678   Bufbyte *strptr = str;
679   *strptr = *ptr++;
680   switch (REP_BYTES_BY_FIRST_BYTE (*strptr))
681     {
682       /* Notice fallthrough. */
683 #ifdef UTF2000
684     case 6: *++strptr = *ptr++;
685     case 5: *++strptr = *ptr++;
686 #endif
687     case 4: *++strptr = *ptr++;
688     case 3: *++strptr = *ptr++;
689     case 2: *++strptr = *ptr;
690       break;
691     default:
692       abort ();
693     }
694   return strptr + 1 - str;
695 }
696
697 \f
698 /************************************************************************/
699 /*                        streams of Emchars                            */
700 /************************************************************************/
701
702 /* Treat a stream as a stream of Emchar's rather than a stream of bytes.
703    The functions below are not meant to be called directly; use
704    the macros in insdel.h. */
705
706 Emchar
707 Lstream_get_emchar_1 (Lstream *stream, int ch)
708 {
709   Bufbyte str[MAX_EMCHAR_LEN];
710   Bufbyte *strptr = str;
711
712   str[0] = (Bufbyte) ch;
713   switch (REP_BYTES_BY_FIRST_BYTE (ch))
714     {
715       /* Notice fallthrough. */
716 #ifdef UTF2000
717     case 6:
718       ch = Lstream_getc (stream);
719       assert (ch >= 0);
720       *++strptr = (Bufbyte) ch;
721     case 5:
722       ch = Lstream_getc (stream);
723       assert (ch >= 0);
724       *++strptr = (Bufbyte) ch;
725 #endif
726     case 4:
727       ch = Lstream_getc (stream);
728       assert (ch >= 0);
729       *++strptr = (Bufbyte) ch;
730     case 3:
731       ch = Lstream_getc (stream);
732       assert (ch >= 0);
733       *++strptr = (Bufbyte) ch;
734     case 2:
735       ch = Lstream_getc (stream);
736       assert (ch >= 0);
737       *++strptr = (Bufbyte) ch;
738       break;
739     default:
740       abort ();
741     }
742   return charptr_emchar (str);
743 }
744
745 int
746 Lstream_fput_emchar (Lstream *stream, Emchar ch)
747 {
748   Bufbyte str[MAX_EMCHAR_LEN];
749   Bytecount len = set_charptr_emchar (str, ch);
750   return Lstream_write (stream, str, len);
751 }
752
753 void
754 Lstream_funget_emchar (Lstream *stream, Emchar ch)
755 {
756   Bufbyte str[MAX_EMCHAR_LEN];
757   Bytecount len = set_charptr_emchar (str, ch);
758   Lstream_unread (stream, str, len);
759 }
760
761 \f
762 /************************************************************************/
763 /*                            charset object                            */
764 /************************************************************************/
765
766 static Lisp_Object
767 mark_charset (Lisp_Object obj, void (*markobj) (Lisp_Object))
768 {
769   struct Lisp_Charset *cs = XCHARSET (obj);
770
771   markobj (cs->short_name);
772   markobj (cs->long_name);
773   markobj (cs->doc_string);
774   markobj (cs->registry);
775   markobj (cs->ccl_program);
776 #ifdef UTF2000
777   markobj (cs->decoding_table);
778   markobj (cs->encoding_table);
779 #endif
780   return cs->name;
781 }
782
783 static void
784 print_charset (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
785 {
786   struct Lisp_Charset *cs = XCHARSET (obj);
787   char buf[200];
788
789   if (print_readably)
790     error ("printing unreadable object #<charset %s 0x%x>",
791            string_data (XSYMBOL (CHARSET_NAME (cs))->name),
792            cs->header.uid);
793
794   write_c_string ("#<charset ", printcharfun);
795   print_internal (CHARSET_NAME (cs), printcharfun, 0);
796   write_c_string (" ", printcharfun);
797   print_internal (CHARSET_SHORT_NAME (cs), printcharfun, 1);
798   write_c_string (" ", printcharfun);
799   print_internal (CHARSET_LONG_NAME (cs), printcharfun, 1);
800   write_c_string (" ", printcharfun);
801   print_internal (CHARSET_DOC_STRING (cs), printcharfun, 1);
802   sprintf (buf, " %s %s cols=%d g%d final='%c' reg=",
803            CHARSET_TYPE (cs) == CHARSET_TYPE_94    ? "94" :
804            CHARSET_TYPE (cs) == CHARSET_TYPE_96    ? "96" :
805            CHARSET_TYPE (cs) == CHARSET_TYPE_94X94 ? "94x94" :
806            "96x96",
807            CHARSET_DIRECTION (cs) == CHARSET_LEFT_TO_RIGHT ? "l2r" : "r2l",
808            CHARSET_COLUMNS (cs),
809            CHARSET_GRAPHIC (cs),
810            CHARSET_FINAL (cs));
811   write_c_string (buf, printcharfun);
812   print_internal (CHARSET_REGISTRY (cs), printcharfun, 0);
813   sprintf (buf, " 0x%x>", cs->header.uid);
814   write_c_string (buf, printcharfun);
815 }
816
817 static const struct lrecord_description charset_description[] = {
818   { XD_LISP_OBJECT, offsetof(struct Lisp_Charset, name), 7 },
819 #ifdef UTF2000
820   { XD_LISP_OBJECT, offsetof(struct Lisp_Charset, decoding_table), 2 },
821 #endif
822   { XD_END }
823 };
824
825 DEFINE_LRECORD_IMPLEMENTATION ("charset", charset,
826                                mark_charset, print_charset, 0, 0, 0,
827                                charset_description,
828                                struct Lisp_Charset);
829
830 /* Make a new charset. */
831
832 static Lisp_Object
833 make_charset (Charset_ID id, Lisp_Object name,
834               unsigned char type, unsigned char columns, unsigned char graphic,
835               Bufbyte final, unsigned char direction, Lisp_Object short_name,
836               Lisp_Object long_name, Lisp_Object doc,
837               Lisp_Object reg,
838               Lisp_Object decoding_table,
839               Emchar ucs_min, Emchar ucs_max,
840               Emchar code_offset, unsigned char byte_offset)
841 {
842   Lisp_Object obj;
843   struct Lisp_Charset *cs =
844     alloc_lcrecord_type (struct Lisp_Charset, &lrecord_charset);
845   XSETCHARSET (obj, cs);
846
847   CHARSET_ID            (cs) = id;
848   CHARSET_NAME          (cs) = name;
849   CHARSET_SHORT_NAME    (cs) = short_name;
850   CHARSET_LONG_NAME     (cs) = long_name;
851   CHARSET_DIRECTION     (cs) = direction;
852   CHARSET_TYPE          (cs) = type;
853   CHARSET_COLUMNS       (cs) = columns;
854   CHARSET_GRAPHIC       (cs) = graphic;
855   CHARSET_FINAL         (cs) = final;
856   CHARSET_DOC_STRING    (cs) = doc;
857   CHARSET_REGISTRY      (cs) = reg;
858   CHARSET_CCL_PROGRAM   (cs) = Qnil;
859   CHARSET_REVERSE_DIRECTION_CHARSET (cs) = Qnil;
860 #ifdef UTF2000
861   CHARSET_DECODING_TABLE(cs) = Qnil;
862   CHARSET_ENCODING_TABLE(cs) = Qnil;
863   CHARSET_UCS_MIN(cs) = ucs_min;
864   CHARSET_UCS_MAX(cs) = ucs_max;
865   CHARSET_CODE_OFFSET(cs) = code_offset;
866   CHARSET_BYTE_OFFSET(cs) = byte_offset;
867 #endif
868
869   switch (CHARSET_TYPE (cs))
870     {
871     case CHARSET_TYPE_94:
872       CHARSET_DIMENSION (cs) = 1;
873       CHARSET_CHARS (cs) = 94;
874       break;
875     case CHARSET_TYPE_96:
876       CHARSET_DIMENSION (cs) = 1;
877       CHARSET_CHARS (cs) = 96;
878       break;
879     case CHARSET_TYPE_94X94:
880       CHARSET_DIMENSION (cs) = 2;
881       CHARSET_CHARS (cs) = 94;
882       break;
883     case CHARSET_TYPE_96X96:
884       CHARSET_DIMENSION (cs) = 2;
885       CHARSET_CHARS (cs) = 96;
886       break;
887 #ifdef UTF2000
888     case CHARSET_TYPE_128:
889       CHARSET_DIMENSION (cs) = 1;
890       CHARSET_CHARS (cs) = 128;
891       break;
892     case CHARSET_TYPE_128X128:
893       CHARSET_DIMENSION (cs) = 2;
894       CHARSET_CHARS (cs) = 128;
895       break;
896     case CHARSET_TYPE_256:
897       CHARSET_DIMENSION (cs) = 1;
898       CHARSET_CHARS (cs) = 256;
899       break;
900     case CHARSET_TYPE_256X256:
901       CHARSET_DIMENSION (cs) = 2;
902       CHARSET_CHARS (cs) = 256;
903       break;
904 #endif
905     }
906
907 #ifndef UTF2000
908   if (id == LEADING_BYTE_ASCII)
909     CHARSET_REP_BYTES (cs) = 1;
910   else if (id < 0xA0)
911     CHARSET_REP_BYTES (cs) = CHARSET_DIMENSION (cs) + 1;
912   else
913     CHARSET_REP_BYTES (cs) = CHARSET_DIMENSION (cs) + 2;
914 #endif
915   
916   if (final)
917     {
918       /* some charsets do not have final characters.  This includes
919          ASCII, Control-1, Composite, and the two faux private
920          charsets. */
921 #if UTF2000
922       if (code_offset == 0)
923         {
924           assert (NILP (charset_by_attributes[type][final]));
925           charset_by_attributes[type][final] = obj;
926         }
927 #else
928       assert (NILP (charset_by_attributes[type][final][direction]));
929       charset_by_attributes[type][final][direction] = obj;
930 #endif
931     }
932
933   assert (NILP (charset_by_leading_byte[id - MIN_LEADING_BYTE]));
934   charset_by_leading_byte[id - MIN_LEADING_BYTE] = obj;
935 #ifndef UTF2000
936   if (id < 0xA0)
937     /* official leading byte */
938     rep_bytes_by_first_byte[id] = CHARSET_REP_BYTES (cs);
939 #endif
940
941   /* Some charsets are "faux" and don't have names or really exist at
942      all except in the leading-byte table. */
943   if (!NILP (name))
944     Fputhash (name, obj, Vcharset_hash_table);
945   return obj;
946 }
947
948 static int
949 get_unallocated_leading_byte (int dimension)
950 {
951   Charset_ID lb;
952
953 #ifdef UTF2000
954   if (next_allocated_leading_byte > MAX_LEADING_BYTE_PRIVATE)
955     lb = 0;
956   else
957     lb = next_allocated_leading_byte++;
958 #else
959   if (dimension == 1)
960     {
961       if (next_allocated_1_byte_leading_byte > MAX_LEADING_BYTE_PRIVATE_1)
962         lb = 0;
963       else
964         lb = next_allocated_1_byte_leading_byte++;
965     }
966   else
967     {
968       if (next_allocated_2_byte_leading_byte > MAX_LEADING_BYTE_PRIVATE_2)
969         lb = 0;
970       else
971         lb = next_allocated_2_byte_leading_byte++;
972     }
973 #endif
974
975   if (!lb)
976     signal_simple_error
977       ("No more character sets free for this dimension",
978        make_int (dimension));
979
980   return lb;
981 }
982
983 #ifdef UTF2000
984 Lisp_Object
985 range_charset_code_point (Lisp_Object charset, Emchar ch)
986 {
987   int d;
988
989   if ((XCHARSET_UCS_MIN (charset) <= ch)
990       && (ch <= XCHARSET_UCS_MAX (charset)))
991     {
992       d = ch - XCHARSET_UCS_MIN (charset) + XCHARSET_CODE_OFFSET (charset);
993                        
994       if (XCHARSET_DIMENSION (charset) == 1)
995         return list1 (make_int (d + XCHARSET_BYTE_OFFSET (charset)));
996       else if (XCHARSET_DIMENSION (charset) == 2)
997         return list2 (make_int (d / XCHARSET_CHARS (charset)
998                                 + XCHARSET_BYTE_OFFSET (charset)),
999                       make_int (d % XCHARSET_CHARS (charset)
1000                                 + XCHARSET_BYTE_OFFSET (charset)));
1001       else if (XCHARSET_DIMENSION (charset) == 3)
1002         return list3 (make_int (d / (XCHARSET_CHARS (charset)
1003                                         * XCHARSET_CHARS (charset))
1004                                 + XCHARSET_BYTE_OFFSET (charset)),
1005                       make_int (d / XCHARSET_CHARS (charset)
1006                                 % XCHARSET_CHARS (charset)
1007                                 + XCHARSET_BYTE_OFFSET (charset)),
1008                       make_int (d % XCHARSET_CHARS (charset)
1009                                 + XCHARSET_BYTE_OFFSET (charset)));
1010       else /* if (XCHARSET_DIMENSION (charset) == 4) */
1011         return list4 (make_int (d / (XCHARSET_CHARS (charset)
1012                                         * XCHARSET_CHARS (charset)
1013                                         * XCHARSET_CHARS (charset))
1014                                 + XCHARSET_BYTE_OFFSET (charset)),
1015                       make_int (d / (XCHARSET_CHARS (charset)
1016                                         * XCHARSET_CHARS (charset))
1017                                 % XCHARSET_CHARS (charset)
1018                                 + XCHARSET_BYTE_OFFSET (charset)),
1019                       make_int (d / XCHARSET_CHARS (charset)
1020                                 % XCHARSET_CHARS (charset)
1021                                 + XCHARSET_BYTE_OFFSET (charset)),
1022                       make_int (d % XCHARSET_CHARS (charset)
1023                                 + XCHARSET_BYTE_OFFSET (charset)));
1024     }
1025   else if (XCHARSET_CODE_OFFSET (charset) == 0)
1026     {
1027       if (XCHARSET_DIMENSION (charset) == 1)
1028         {
1029           if (XCHARSET_CHARS (charset) == 94)
1030             {
1031               if (((d = ch - (MIN_CHAR_94
1032                               + (XCHARSET_FINAL (charset) - '0') * 94)) >= 0)
1033                   && (d < 94))
1034                 return list1 (make_int (d + 33));
1035             }
1036           else if (XCHARSET_CHARS (charset) == 96)
1037             {
1038               if (((d = ch - (MIN_CHAR_96
1039                               + (XCHARSET_FINAL (charset) - '0') * 96)) >= 0)
1040                   && (d < 96))
1041                 return list1 (make_int (d + 32));
1042             }
1043           else
1044             return Qnil;
1045         }
1046       else if (XCHARSET_DIMENSION (charset) == 2)
1047         {
1048           if (XCHARSET_CHARS (charset) == 94)
1049             {
1050               if (((d = ch - (MIN_CHAR_94x94
1051                               + (XCHARSET_FINAL (charset) - '0') * 94 * 94))
1052                    >= 0)
1053                   && (d < 94 * 94))
1054                 return list2 ((d / 94) + 33, d % 94 + 33);
1055             }
1056           else if (XCHARSET_CHARS (charset) == 96)
1057             {
1058               if (((d = ch - (MIN_CHAR_96x96
1059                               + (XCHARSET_FINAL (charset) - '0') * 96 * 96))
1060                    >= 0)
1061                   && (d < 96 * 96))
1062                 return list2 ((d / 96) + 32, d % 96 + 32);
1063             }
1064         }
1065     }
1066   return Qnil;
1067 }
1068
1069 Lisp_Object
1070 charset_code_point (Lisp_Object charset, Emchar ch)
1071 {
1072   Lisp_Object cdef = get_char_code_table (ch, Vcharacter_attribute_table);
1073
1074   if (!EQ (cdef, Qnil))
1075     {
1076       Lisp_Object field = Fassq (charset, cdef);
1077
1078       if (!EQ (field, Qnil))
1079         return Fcdr (field);
1080     }
1081   return range_charset_code_point (charset, ch);
1082 }
1083
1084 Lisp_Object Vdefault_coded_charset_priority_list;
1085 #endif
1086
1087 \f
1088 /************************************************************************/
1089 /*                      Basic charset Lisp functions                    */
1090 /************************************************************************/
1091
1092 DEFUN ("charsetp", Fcharsetp, 1, 1, 0, /*
1093 Return non-nil if OBJECT is a charset.
1094 */
1095        (object))
1096 {
1097   return CHARSETP (object) ? Qt : Qnil;
1098 }
1099
1100 DEFUN ("find-charset", Ffind_charset, 1, 1, 0, /*
1101 Retrieve the charset of the given name.
1102 If CHARSET-OR-NAME is a charset object, it is simply returned.
1103 Otherwise, CHARSET-OR-NAME should be a symbol.  If there is no such charset,
1104 nil is returned.  Otherwise the associated charset object is returned.
1105 */
1106        (charset_or_name))
1107 {
1108   if (CHARSETP (charset_or_name))
1109     return charset_or_name;
1110
1111   CHECK_SYMBOL (charset_or_name);
1112   return Fgethash (charset_or_name, Vcharset_hash_table, Qnil);
1113 }
1114
1115 DEFUN ("get-charset", Fget_charset, 1, 1, 0, /*
1116 Retrieve the charset of the given name.
1117 Same as `find-charset' except an error is signalled if there is no such
1118 charset instead of returning nil.
1119 */
1120        (name))
1121 {
1122   Lisp_Object charset = Ffind_charset (name);
1123
1124   if (NILP (charset))
1125     signal_simple_error ("No such charset", name);
1126   return charset;
1127 }
1128
1129 /* We store the charsets in hash tables with the names as the key and the
1130    actual charset object as the value.  Occasionally we need to use them
1131    in a list format.  These routines provide us with that. */
1132 struct charset_list_closure
1133 {
1134   Lisp_Object *charset_list;
1135 };
1136
1137 static int
1138 add_charset_to_list_mapper (Lisp_Object key, Lisp_Object value,
1139                             void *charset_list_closure)
1140 {
1141   /* This function can GC */
1142   struct charset_list_closure *chcl =
1143     (struct charset_list_closure*) charset_list_closure;
1144   Lisp_Object *charset_list = chcl->charset_list;
1145
1146   *charset_list = Fcons (XCHARSET_NAME (value), *charset_list);
1147   return 0;
1148 }
1149
1150 DEFUN ("charset-list", Fcharset_list, 0, 0, 0, /*
1151 Return a list of the names of all defined charsets.
1152 */
1153        ())
1154 {
1155   Lisp_Object charset_list = Qnil;
1156   struct gcpro gcpro1;
1157   struct charset_list_closure charset_list_closure;
1158
1159   GCPRO1 (charset_list);
1160   charset_list_closure.charset_list = &charset_list;
1161   elisp_maphash (add_charset_to_list_mapper, Vcharset_hash_table,
1162                  &charset_list_closure);
1163   UNGCPRO;
1164
1165   return charset_list;
1166 }
1167
1168 DEFUN ("charset-name", Fcharset_name, 1, 1, 0, /*
1169 Return the name of the given charset.
1170 */
1171        (charset))
1172 {
1173   return XCHARSET_NAME (Fget_charset (charset));
1174 }
1175
1176 DEFUN ("make-charset", Fmake_charset, 3, 3, 0, /*
1177 Define a new character set.
1178 This function is for use with Mule support.
1179 NAME is a symbol, the name by which the character set is normally referred.
1180 DOC-STRING is a string describing the character set.
1181 PROPS is a property list, describing the specific nature of the
1182 character set.  Recognized properties are:
1183
1184 'short-name     Short version of the charset name (ex: Latin-1)
1185 'long-name      Long version of the charset name (ex: ISO8859-1 (Latin-1))
1186 'registry       A regular expression matching the font registry field for
1187                 this character set.
1188 'dimension      Number of octets used to index a character in this charset.
1189                 Either 1 or 2.  Defaults to 1.
1190 'columns        Number of columns used to display a character in this charset.
1191                 Only used in TTY mode. (Under X, the actual width of a
1192                 character can be derived from the font used to display the
1193                 characters.) If unspecified, defaults to the dimension
1194                 (this is almost always the correct value).
1195 'chars          Number of characters in each dimension (94 or 96).
1196                 Defaults to 94.  Note that if the dimension is 2, the
1197                 character set thus described is 94x94 or 96x96.
1198 'final          Final byte of ISO 2022 escape sequence.  Must be
1199                 supplied.  Each combination of (DIMENSION, CHARS) defines a
1200                 separate namespace for final bytes.  Note that ISO
1201                 2022 restricts the final byte to the range
1202                 0x30 - 0x7E if dimension == 1, and 0x30 - 0x5F if
1203                 dimension == 2.  Note also that final bytes in the range
1204                 0x30 - 0x3F are reserved for user-defined (not official)
1205                 character sets.
1206 'graphic        0 (use left half of font on output) or 1 (use right half
1207                 of font on output).  Defaults to 0.  For example, for
1208                 a font whose registry is ISO8859-1, the left half
1209                 (octets 0x20 - 0x7F) is the `ascii' character set, while
1210                 the right half (octets 0xA0 - 0xFF) is the `latin-1'
1211                 character set.  With 'graphic set to 0, the octets
1212                 will have their high bit cleared; with it set to 1,
1213                 the octets will have their high bit set.
1214 'direction      'l2r (left-to-right) or 'r2l (right-to-left).
1215                 Defaults to 'l2r.
1216 'ccl-program    A compiled CCL program used to convert a character in
1217                 this charset into an index into the font.  This is in
1218                 addition to the 'graphic property.  The CCL program
1219                 is passed the octets of the character, with the high
1220                 bit cleared and set depending upon whether the value
1221                 of the 'graphic property is 0 or 1.
1222 */
1223        (name, doc_string, props))
1224 {
1225   int id, dimension = 1, chars = 94, graphic = 0, final = 0, columns = -1;
1226   int direction = CHARSET_LEFT_TO_RIGHT;
1227   int type;
1228   Lisp_Object registry = Qnil;
1229   Lisp_Object charset;
1230   Lisp_Object rest, keyword, value;
1231   Lisp_Object ccl_program = Qnil;
1232   Lisp_Object short_name = Qnil, long_name = Qnil;
1233 #ifdef UTF2000
1234   unsigned char byte_offset = 0;
1235 #endif
1236
1237   CHECK_SYMBOL (name);
1238   if (!NILP (doc_string))
1239     CHECK_STRING (doc_string);
1240
1241   charset = Ffind_charset (name);
1242   if (!NILP (charset))
1243     signal_simple_error ("Cannot redefine existing charset", name);
1244
1245   EXTERNAL_PROPERTY_LIST_LOOP (rest, keyword, value, props)
1246     {
1247       if (EQ (keyword, Qshort_name))
1248         {
1249           CHECK_STRING (value);
1250           short_name = value;
1251         }
1252
1253       if (EQ (keyword, Qlong_name))
1254         {
1255           CHECK_STRING (value);
1256           long_name = value;
1257         }
1258
1259       else if (EQ (keyword, Qdimension))
1260         {
1261           CHECK_INT (value);
1262           dimension = XINT (value);
1263           if (dimension < 1 || dimension > 2)
1264             signal_simple_error ("Invalid value for 'dimension", value);
1265         }
1266
1267       else if (EQ (keyword, Qchars))
1268         {
1269           CHECK_INT (value);
1270           chars = XINT (value);
1271           if (chars != 94 && chars != 96)
1272             signal_simple_error ("Invalid value for 'chars", value);
1273         }
1274
1275       else if (EQ (keyword, Qcolumns))
1276         {
1277           CHECK_INT (value);
1278           columns = XINT (value);
1279           if (columns != 1 && columns != 2)
1280             signal_simple_error ("Invalid value for 'columns", value);
1281         }
1282
1283       else if (EQ (keyword, Qgraphic))
1284         {
1285           CHECK_INT (value);
1286           graphic = XINT (value);
1287 #ifdef UTF2000
1288           if (graphic < 0 || graphic > 2)
1289 #else
1290           if (graphic < 0 || graphic > 1)
1291 #endif
1292             signal_simple_error ("Invalid value for 'graphic", value);
1293         }
1294
1295       else if (EQ (keyword, Qregistry))
1296         {
1297           CHECK_STRING (value);
1298           registry = value;
1299         }
1300
1301       else if (EQ (keyword, Qdirection))
1302         {
1303           if (EQ (value, Ql2r))
1304             direction = CHARSET_LEFT_TO_RIGHT;
1305           else if (EQ (value, Qr2l))
1306             direction = CHARSET_RIGHT_TO_LEFT;
1307           else
1308             signal_simple_error ("Invalid value for 'direction", value);
1309         }
1310
1311       else if (EQ (keyword, Qfinal))
1312         {
1313           CHECK_CHAR_COERCE_INT (value);
1314           final = XCHAR (value);
1315           if (final < '0' || final > '~')
1316             signal_simple_error ("Invalid value for 'final", value);
1317         }
1318
1319       else if (EQ (keyword, Qccl_program))
1320         {
1321           CHECK_VECTOR (value);
1322           ccl_program = value;
1323         }
1324
1325       else
1326         signal_simple_error ("Unrecognized property", keyword);
1327     }
1328
1329   if (!final)
1330     error ("'final must be specified");
1331   if (dimension == 2 && final > 0x5F)
1332     signal_simple_error
1333       ("Final must be in the range 0x30 - 0x5F for dimension == 2",
1334        make_char (final));
1335
1336   if (dimension == 1)
1337     type = (chars == 94) ? CHARSET_TYPE_94    : CHARSET_TYPE_96;
1338   else
1339     type = (chars == 94) ? CHARSET_TYPE_94X94 : CHARSET_TYPE_96X96;
1340
1341   if (!NILP (CHARSET_BY_ATTRIBUTES (type, final, CHARSET_LEFT_TO_RIGHT)) ||
1342       !NILP (CHARSET_BY_ATTRIBUTES (type, final, CHARSET_RIGHT_TO_LEFT)))
1343     error
1344       ("Character set already defined for this DIMENSION/CHARS/FINAL combo");
1345
1346   id = get_unallocated_leading_byte (dimension);
1347
1348   if (NILP (doc_string))
1349     doc_string = build_string ("");
1350
1351   if (NILP (registry))
1352     registry = build_string ("");
1353
1354   if (NILP (short_name))
1355     XSETSTRING (short_name, XSYMBOL (name)->name);
1356
1357   if (NILP (long_name))
1358     long_name = doc_string;
1359
1360   if (columns == -1)
1361     columns = dimension;
1362   charset = make_charset (id, name, type, columns, graphic,
1363                           final, direction, short_name, long_name,
1364                           doc_string, registry,
1365                           Qnil, 0, 0, 0, byte_offset);
1366   if (!NILP (ccl_program))
1367     XCHARSET_CCL_PROGRAM (charset) = ccl_program;
1368   return charset;
1369 }
1370
1371 DEFUN ("make-reverse-direction-charset", Fmake_reverse_direction_charset,
1372        2, 2, 0, /*
1373 Make a charset equivalent to CHARSET but which goes in the opposite direction.
1374 NEW-NAME is the name of the new charset.  Return the new charset.
1375 */
1376        (charset, new_name))
1377 {
1378   Lisp_Object new_charset = Qnil;
1379   int id, dimension, columns, graphic, final;
1380   int direction, type;
1381   Lisp_Object registry, doc_string, short_name, long_name;
1382   struct Lisp_Charset *cs;
1383
1384   charset = Fget_charset (charset);
1385   if (!NILP (XCHARSET_REVERSE_DIRECTION_CHARSET (charset)))
1386     signal_simple_error ("Charset already has reverse-direction charset",
1387                          charset);
1388
1389   CHECK_SYMBOL (new_name);
1390   if (!NILP (Ffind_charset (new_name)))
1391     signal_simple_error ("Cannot redefine existing charset", new_name);
1392
1393   cs = XCHARSET (charset);
1394
1395   type      = CHARSET_TYPE      (cs);
1396   columns   = CHARSET_COLUMNS   (cs);
1397   dimension = CHARSET_DIMENSION (cs);
1398   id = get_unallocated_leading_byte (dimension);
1399
1400   graphic = CHARSET_GRAPHIC (cs);
1401   final = CHARSET_FINAL (cs);
1402   direction = CHARSET_RIGHT_TO_LEFT;
1403   if (CHARSET_DIRECTION (cs) == CHARSET_RIGHT_TO_LEFT)
1404     direction = CHARSET_LEFT_TO_RIGHT;
1405   doc_string = CHARSET_DOC_STRING (cs);
1406   short_name = CHARSET_SHORT_NAME (cs);
1407   long_name = CHARSET_LONG_NAME (cs);
1408   registry = CHARSET_REGISTRY (cs);
1409
1410   new_charset = make_charset (id, new_name, type, columns,
1411                               graphic, final, direction, short_name, long_name,
1412                               doc_string, registry,
1413 #ifdef UTF2000
1414                               CHARSET_DECODING_TABLE(cs),
1415                               CHARSET_UCS_MIN(cs),
1416                               CHARSET_UCS_MAX(cs),
1417                               CHARSET_CODE_OFFSET(cs),
1418                               CHARSET_BYTE_OFFSET(cs)
1419 #else
1420                               Qnil, 0, 0, 0, 0
1421 #endif
1422 );
1423
1424   CHARSET_REVERSE_DIRECTION_CHARSET (cs) = new_charset;
1425   XCHARSET_REVERSE_DIRECTION_CHARSET (new_charset) = charset;
1426
1427   return new_charset;
1428 }
1429
1430 DEFUN ("define-charset-alias", Fdefine_charset_alias, 2, 2, 0, /*
1431 Define symbol ALIAS as an alias for CHARSET.
1432 */
1433        (alias, charset))
1434 {
1435   CHECK_SYMBOL (alias);
1436   charset = Fget_charset (charset);
1437   return Fputhash (alias, charset, Vcharset_hash_table);
1438 }
1439
1440 /* #### Reverse direction charsets not yet implemented.  */
1441 #if 0
1442 DEFUN ("charset-reverse-direction-charset", Fcharset_reverse_direction_charset,
1443        1, 1, 0, /*
1444 Return the reverse-direction charset parallel to CHARSET, if any.
1445 This is the charset with the same properties (in particular, the same
1446 dimension, number of characters per dimension, and final byte) as
1447 CHARSET but whose characters are displayed in the opposite direction.
1448 */
1449        (charset))
1450 {
1451   charset = Fget_charset (charset);
1452   return XCHARSET_REVERSE_DIRECTION_CHARSET (charset);
1453 }
1454 #endif
1455
1456 DEFUN ("charset-from-attributes", Fcharset_from_attributes, 3, 4, 0, /*
1457 Return a charset with the given DIMENSION, CHARS, FINAL, and DIRECTION.
1458 If DIRECTION is omitted, both directions will be checked (left-to-right
1459 will be returned if character sets exist for both directions).
1460 */
1461        (dimension, chars, final, direction))
1462 {
1463   int dm, ch, fi, di = -1;
1464   int type;
1465   Lisp_Object obj = Qnil;
1466
1467   CHECK_INT (dimension);
1468   dm = XINT (dimension);
1469   if (dm < 1 || dm > 2)
1470     signal_simple_error ("Invalid value for DIMENSION", dimension);
1471
1472   CHECK_INT (chars);
1473   ch = XINT (chars);
1474   if (ch != 94 && ch != 96)
1475     signal_simple_error ("Invalid value for CHARS", chars);
1476
1477   CHECK_CHAR_COERCE_INT (final);
1478   fi = XCHAR (final);
1479   if (fi < '0' || fi > '~')
1480     signal_simple_error ("Invalid value for FINAL", final);
1481
1482   if (EQ (direction, Ql2r))
1483     di = CHARSET_LEFT_TO_RIGHT;
1484   else if (EQ (direction, Qr2l))
1485     di = CHARSET_RIGHT_TO_LEFT;
1486   else if (!NILP (direction))
1487     signal_simple_error ("Invalid value for DIRECTION", direction);
1488
1489   if (dm == 2 && fi > 0x5F)
1490     signal_simple_error
1491       ("Final must be in the range 0x30 - 0x5F for dimension == 2", final);
1492
1493   if (dm == 1)
1494     type = (ch == 94) ? CHARSET_TYPE_94    : CHARSET_TYPE_96;
1495   else
1496     type = (ch == 94) ? CHARSET_TYPE_94X94 : CHARSET_TYPE_96X96;
1497
1498   if (di == -1)
1499     {
1500       obj = CHARSET_BY_ATTRIBUTES (type, fi, CHARSET_LEFT_TO_RIGHT);
1501       if (NILP (obj))
1502         obj = CHARSET_BY_ATTRIBUTES (type, fi, CHARSET_RIGHT_TO_LEFT);
1503     }
1504   else
1505     obj = CHARSET_BY_ATTRIBUTES (type, fi, di);
1506
1507   if (CHARSETP (obj))
1508     return XCHARSET_NAME (obj);
1509   return obj;
1510 }
1511
1512 DEFUN ("charset-short-name", Fcharset_short_name, 1, 1, 0, /*
1513 Return short name of CHARSET.
1514 */
1515        (charset))
1516 {
1517   return XCHARSET_SHORT_NAME (Fget_charset (charset));
1518 }
1519
1520 DEFUN ("charset-long-name", Fcharset_long_name, 1, 1, 0, /*
1521 Return long name of CHARSET.
1522 */
1523        (charset))
1524 {
1525   return XCHARSET_LONG_NAME (Fget_charset (charset));
1526 }
1527
1528 DEFUN ("charset-description", Fcharset_description, 1, 1, 0, /*
1529 Return description of CHARSET.
1530 */
1531        (charset))
1532 {
1533   return XCHARSET_DOC_STRING (Fget_charset (charset));
1534 }
1535
1536 DEFUN ("charset-dimension", Fcharset_dimension, 1, 1, 0, /*
1537 Return dimension of CHARSET.
1538 */
1539        (charset))
1540 {
1541   return make_int (XCHARSET_DIMENSION (Fget_charset (charset)));
1542 }
1543
1544 DEFUN ("charset-property", Fcharset_property, 2, 2, 0, /*
1545 Return property PROP of CHARSET.
1546 Recognized properties are those listed in `make-charset', as well as
1547 'name and 'doc-string.
1548 */
1549        (charset, prop))
1550 {
1551   struct Lisp_Charset *cs;
1552
1553   charset = Fget_charset (charset);
1554   cs = XCHARSET (charset);
1555
1556   CHECK_SYMBOL (prop);
1557   if (EQ (prop, Qname))        return CHARSET_NAME (cs);
1558   if (EQ (prop, Qshort_name))  return CHARSET_SHORT_NAME (cs);
1559   if (EQ (prop, Qlong_name))   return CHARSET_LONG_NAME (cs);
1560   if (EQ (prop, Qdoc_string))  return CHARSET_DOC_STRING (cs);
1561   if (EQ (prop, Qdimension))   return make_int (CHARSET_DIMENSION (cs));
1562   if (EQ (prop, Qcolumns))     return make_int (CHARSET_COLUMNS (cs));
1563   if (EQ (prop, Qgraphic))     return make_int (CHARSET_GRAPHIC (cs));
1564   if (EQ (prop, Qfinal))       return make_char (CHARSET_FINAL (cs));
1565   if (EQ (prop, Qchars))       return make_int (CHARSET_CHARS (cs));
1566   if (EQ (prop, Qregistry))    return CHARSET_REGISTRY (cs);
1567   if (EQ (prop, Qccl_program)) return CHARSET_CCL_PROGRAM (cs);
1568   if (EQ (prop, Qdirection))
1569     return CHARSET_DIRECTION (cs) == CHARSET_LEFT_TO_RIGHT ? Ql2r : Qr2l;
1570   if (EQ (prop, Qreverse_direction_charset))
1571     {
1572       Lisp_Object obj = CHARSET_REVERSE_DIRECTION_CHARSET (cs);
1573       if (NILP (obj))
1574         return Qnil;
1575       else
1576         return XCHARSET_NAME (obj);
1577     }
1578   signal_simple_error ("Unrecognized charset property name", prop);
1579   return Qnil; /* not reached */
1580 }
1581
1582 DEFUN ("charset-id", Fcharset_id, 1, 1, 0, /*
1583 Return charset identification number of CHARSET.
1584 */
1585         (charset))
1586 {
1587   return make_int(XCHARSET_LEADING_BYTE (Fget_charset (charset)));
1588 }
1589
1590 /* #### We need to figure out which properties we really want to
1591    allow to be set. */
1592
1593 DEFUN ("set-charset-ccl-program", Fset_charset_ccl_program, 2, 2, 0, /*
1594 Set the 'ccl-program property of CHARSET to CCL-PROGRAM.
1595 */
1596        (charset, ccl_program))
1597 {
1598   charset = Fget_charset (charset);
1599   CHECK_VECTOR (ccl_program);
1600   XCHARSET_CCL_PROGRAM (charset) = ccl_program;
1601   return Qnil;
1602 }
1603
1604 static void
1605 invalidate_charset_font_caches (Lisp_Object charset)
1606 {
1607   /* Invalidate font cache entries for charset on all devices. */
1608   Lisp_Object devcons, concons, hash_table;
1609   DEVICE_LOOP_NO_BREAK (devcons, concons)
1610     {
1611       struct device *d = XDEVICE (XCAR (devcons));
1612       hash_table = Fgethash (charset, d->charset_font_cache, Qunbound);
1613       if (!UNBOUNDP (hash_table))
1614         Fclrhash (hash_table);
1615     }
1616 }
1617
1618 DEFUN ("set-charset-registry", Fset_charset_registry, 2, 2, 0, /*
1619 Set the 'registry property of CHARSET to REGISTRY.
1620 */
1621        (charset, registry))
1622 {
1623   charset = Fget_charset (charset);
1624   CHECK_STRING (registry);
1625   XCHARSET_REGISTRY (charset) = registry;
1626   invalidate_charset_font_caches (charset);
1627   face_property_was_changed (Vdefault_face, Qfont, Qglobal);
1628   return Qnil;
1629 }
1630
1631 #ifdef UTF2000
1632 DEFUN ("charset-mapping-table", Fcharset_mapping_table, 1, 1, 0, /*
1633 Return mapping-table of CHARSET.
1634 */
1635        (charset))
1636 {
1637   return XCHARSET_DECODING_TABLE (Fget_charset (charset));
1638 }
1639
1640 DEFUN ("set-charset-mapping-table", Fset_charset_mapping_table, 2, 2, 0, /*
1641 Set mapping-table of CHARSET to TABLE.
1642 */
1643        (charset, table))
1644 {
1645   struct Lisp_Charset *cs;
1646   Lisp_Object old_table;
1647   size_t i;
1648
1649   charset = Fget_charset (charset);
1650   cs = XCHARSET (charset);
1651
1652   if (EQ (table, Qnil))
1653     {
1654       CHARSET_DECODING_TABLE(cs) = table;
1655       CHARSET_ENCODING_TABLE(cs) = Qnil;
1656       return table;
1657     }
1658   else if (VECTORP (table))
1659     {
1660       if (XVECTOR_LENGTH (table) > CHARSET_CHARS (cs))
1661         args_out_of_range (table, make_int (CHARSET_CHARS (cs)));
1662       old_table = CHARSET_ENCODING_TABLE(cs);
1663       CHARSET_DECODING_TABLE(cs) = table;
1664     }
1665   else
1666     signal_error (Qwrong_type_argument,
1667                   list2 (build_translated_string ("vector-or-nil-p"),
1668                          table));
1669   /* signal_simple_error ("Wrong type argument: vector-or-nil-p", table); */
1670
1671   switch (CHARSET_DIMENSION (cs))
1672     {
1673     case 1:
1674       CHARSET_ENCODING_TABLE(cs) = make_char_code_table (Qnil);
1675       for (i = 0; i < XVECTOR_LENGTH (table); i++)
1676         {
1677           Lisp_Object c = XVECTOR_DATA(table)[i];
1678
1679           if (CHARP (c))
1680             {
1681               put_char_code_table (XCHAR (c),
1682                                    make_int (i + CHARSET_BYTE_OFFSET (cs)),
1683                                    CHARSET_ENCODING_TABLE(cs));
1684               Fput_char_attribute (c, charset,
1685                                    list1
1686                                    (make_int (i + CHARSET_BYTE_OFFSET (cs))));
1687             }
1688         }
1689       break;
1690     case 2:
1691       CHARSET_ENCODING_TABLE(cs) = make_char_code_table (Qnil);
1692       for (i = 0; i < XVECTOR_LENGTH (table); i++)
1693         {
1694           Lisp_Object v = XVECTOR_DATA(table)[i];
1695
1696           if (VECTORP (v))
1697             {
1698               size_t j;
1699
1700               if (XVECTOR_LENGTH (v) > CHARSET_CHARS (cs))
1701                 {
1702                   CHARSET_DECODING_TABLE(cs) = old_table;
1703                   args_out_of_range (v, make_int (CHARSET_CHARS (cs)));
1704                 }
1705               for (j = 0; j < XVECTOR_LENGTH (v); j++)
1706                 {
1707                   Lisp_Object c = XVECTOR_DATA(v)[j];
1708
1709                   if (CHARP (c))
1710                     {
1711                       put_char_code_table
1712                         (XCHAR (c),
1713                          make_int (( (i + CHARSET_BYTE_OFFSET (cs)) << 8)
1714                                    | (j + CHARSET_BYTE_OFFSET (cs))),
1715                          CHARSET_ENCODING_TABLE(cs));
1716                       Fput_char_attribute (c, charset,
1717                                            list2
1718                                            (make_int
1719                                             (i + CHARSET_BYTE_OFFSET (cs)),
1720                                             make_int
1721                                             (j + CHARSET_BYTE_OFFSET (cs))));
1722                     }
1723                 }
1724             }
1725           else if (CHARP (v))
1726             {
1727               put_char_code_table (XCHAR (v),
1728                                    make_int (i + CHARSET_BYTE_OFFSET (cs)),
1729                                    CHARSET_ENCODING_TABLE(cs));
1730               Fput_char_attribute (v, charset,
1731                                    list1
1732                                    (make_int (i + CHARSET_BYTE_OFFSET (cs))));
1733             }
1734         }
1735       break;
1736     }
1737   return table;
1738 }
1739 #endif
1740
1741 \f
1742 /************************************************************************/
1743 /*              Lisp primitives for working with characters             */
1744 /************************************************************************/
1745
1746 DEFUN ("make-char", Fmake_char, 2, 3, 0, /*
1747 Make a character from CHARSET and octets ARG1 and ARG2.
1748 ARG2 is required only for characters from two-dimensional charsets.
1749 For example, (make-char 'latin-iso8859-2 185) will return the Latin 2
1750 character s with caron.
1751 */
1752        (charset, arg1, arg2))
1753 {
1754   struct Lisp_Charset *cs;
1755   int a1, a2;
1756   int lowlim, highlim;
1757
1758   charset = Fget_charset (charset);
1759   cs = XCHARSET (charset);
1760
1761   if      (EQ (charset, Vcharset_ascii))     lowlim =  0, highlim = 127;
1762   else if (EQ (charset, Vcharset_control_1)) lowlim =  0, highlim =  31;
1763 #ifdef UTF2000
1764   else if (CHARSET_CHARS (cs) == 256)        lowlim =  0, highlim = 255;
1765 #endif
1766   else if (CHARSET_CHARS (cs) == 94)         lowlim = 33, highlim = 126;
1767   else  /* CHARSET_CHARS (cs) == 96) */      lowlim = 32, highlim = 127;
1768
1769   CHECK_INT (arg1);
1770   /* It is useful (and safe, according to Olivier Galibert) to strip
1771      the 8th bit off ARG1 and ARG2 becaue it allows programmers to
1772      write (make-char 'latin-iso8859-2 CODE) where code is the actual
1773      Latin 2 code of the character.  */
1774 #ifdef UTF2000
1775   a1 = XINT (arg1);
1776   if (highlim < 128)
1777     a1 &= 0x7f;
1778 #else
1779   a1 = XINT (arg1);
1780 #endif
1781   if (a1 < lowlim || a1 > highlim)
1782     args_out_of_range_3 (arg1, make_int (lowlim), make_int (highlim));
1783
1784   if (CHARSET_DIMENSION (cs) == 1)
1785     {
1786       if (!NILP (arg2))
1787         signal_simple_error
1788           ("Charset is of dimension one; second octet must be nil", arg2);
1789       return make_char (MAKE_CHAR (charset, a1, 0));
1790     }
1791
1792   CHECK_INT (arg2);
1793 #ifdef UTF2000
1794   a2 = XINT (arg2);
1795   if (highlim < 128)
1796     a2 &= 0x7f;
1797 #else
1798   a2 = XINT (arg2) & 0x7f;
1799 #endif
1800   if (a2 < lowlim || a2 > highlim)
1801     args_out_of_range_3 (arg2, make_int (lowlim), make_int (highlim));
1802
1803   return make_char (MAKE_CHAR (charset, a1, a2));
1804 }
1805
1806 DEFUN ("char-charset", Fchar_charset, 1, 1, 0, /*
1807 Return the character set of char CH.
1808 */
1809        (ch))
1810 {
1811   CHECK_CHAR_COERCE_INT (ch);
1812
1813   return XCHARSET_NAME (CHAR_CHARSET (XCHAR (ch)));
1814 }
1815
1816 DEFUN ("split-char", Fsplit_char, 1, 1, 0, /*
1817 Return list of charset and one or two position-codes of CHAR.
1818 */
1819        (character))
1820 {
1821   /* This function can GC */
1822   struct gcpro gcpro1, gcpro2;
1823   Lisp_Object charset = Qnil;
1824   Lisp_Object rc = Qnil;
1825   int c1, c2;
1826
1827   GCPRO2 (charset, rc);
1828   CHECK_CHAR_COERCE_INT (character);
1829
1830   BREAKUP_CHAR (XCHAR (character), charset, c1, c2);
1831
1832   if (XCHARSET_DIMENSION (Fget_charset (charset)) == 2)
1833     {
1834       rc = list3 (XCHARSET_NAME (charset), make_int (c1), make_int (c2));
1835     }
1836   else
1837     {
1838       rc = list2 (XCHARSET_NAME (charset), make_int (c1));
1839     }
1840   UNGCPRO;
1841
1842   return rc;
1843 }
1844
1845 \f
1846 #ifdef ENABLE_COMPOSITE_CHARS
1847 /************************************************************************/
1848 /*                     composite character functions                    */
1849 /************************************************************************/
1850
1851 Emchar
1852 lookup_composite_char (Bufbyte *str, int len)
1853 {
1854   Lisp_Object lispstr = make_string (str, len);
1855   Lisp_Object ch = Fgethash (lispstr,
1856                              Vcomposite_char_string2char_hash_table,
1857                              Qunbound);
1858   Emchar emch;
1859
1860   if (UNBOUNDP (ch))
1861     {
1862       if (composite_char_row_next >= 128)
1863         signal_simple_error ("No more composite chars available", lispstr);
1864       emch = MAKE_CHAR (Vcharset_composite, composite_char_row_next,
1865                         composite_char_col_next);
1866       Fputhash (make_char (emch), lispstr,
1867                 Vcomposite_char_char2string_hash_table);
1868       Fputhash (lispstr, make_char (emch),
1869                 Vcomposite_char_string2char_hash_table);
1870       composite_char_col_next++;
1871       if (composite_char_col_next >= 128)
1872         {
1873           composite_char_col_next = 32;
1874           composite_char_row_next++;
1875         }
1876     }
1877   else
1878     emch = XCHAR (ch);
1879   return emch;
1880 }
1881
1882 Lisp_Object
1883 composite_char_string (Emchar ch)
1884 {
1885   Lisp_Object str = Fgethash (make_char (ch),
1886                               Vcomposite_char_char2string_hash_table,
1887                               Qunbound);
1888   assert (!UNBOUNDP (str));
1889   return str;
1890 }
1891
1892 xxDEFUN ("make-composite-char", Fmake_composite_char, 1, 1, 0, /*
1893 Convert a string into a single composite character.
1894 The character is the result of overstriking all the characters in
1895 the string.
1896 */
1897        (string))
1898 {
1899   CHECK_STRING (string);
1900   return make_char (lookup_composite_char (XSTRING_DATA (string),
1901                                            XSTRING_LENGTH (string)));
1902 }
1903
1904 xxDEFUN ("composite-char-string", Fcomposite_char_string, 1, 1, 0, /*
1905 Return a string of the characters comprising a composite character.
1906 */
1907        (ch))
1908 {
1909   Emchar emch;
1910
1911   CHECK_CHAR (ch);
1912   emch = XCHAR (ch);
1913   if (CHAR_LEADING_BYTE (emch) != LEADING_BYTE_COMPOSITE)
1914     signal_simple_error ("Must be composite char", ch);
1915   return composite_char_string (emch);
1916 }
1917 #endif /* ENABLE_COMPOSITE_CHARS */
1918
1919 \f
1920 /************************************************************************/
1921 /*                            initialization                            */
1922 /************************************************************************/
1923
1924 void
1925 syms_of_mule_charset (void)
1926 {
1927   DEFSUBR (Fcharsetp);
1928   DEFSUBR (Ffind_charset);
1929   DEFSUBR (Fget_charset);
1930   DEFSUBR (Fcharset_list);
1931   DEFSUBR (Fcharset_name);
1932   DEFSUBR (Fmake_charset);
1933   DEFSUBR (Fmake_reverse_direction_charset);
1934   /*  DEFSUBR (Freverse_direction_charset); */
1935   DEFSUBR (Fdefine_charset_alias);
1936   DEFSUBR (Fcharset_from_attributes);
1937   DEFSUBR (Fcharset_short_name);
1938   DEFSUBR (Fcharset_long_name);
1939   DEFSUBR (Fcharset_description);
1940   DEFSUBR (Fcharset_dimension);
1941   DEFSUBR (Fcharset_property);
1942   DEFSUBR (Fcharset_id);
1943   DEFSUBR (Fset_charset_ccl_program);
1944   DEFSUBR (Fset_charset_registry);
1945 #ifdef UTF2000
1946   DEFSUBR (Fchar_attribute_alist);
1947   DEFSUBR (Fget_char_attribute);
1948   DEFSUBR (Fput_char_attribute);
1949   DEFSUBR (Fcharset_mapping_table);
1950   DEFSUBR (Fset_charset_mapping_table);
1951 #endif
1952
1953   DEFSUBR (Fmake_char);
1954   DEFSUBR (Fchar_charset);
1955   DEFSUBR (Fsplit_char);
1956
1957 #ifdef ENABLE_COMPOSITE_CHARS
1958   DEFSUBR (Fmake_composite_char);
1959   DEFSUBR (Fcomposite_char_string);
1960 #endif
1961
1962   defsymbol (&Qcharsetp, "charsetp");
1963   defsymbol (&Qregistry, "registry");
1964   defsymbol (&Qfinal, "final");
1965   defsymbol (&Qgraphic, "graphic");
1966   defsymbol (&Qdirection, "direction");
1967   defsymbol (&Qreverse_direction_charset, "reverse-direction-charset");
1968   defsymbol (&Qshort_name, "short-name");
1969   defsymbol (&Qlong_name, "long-name");
1970
1971   defsymbol (&Ql2r, "l2r");
1972   defsymbol (&Qr2l, "r2l");
1973
1974   /* Charsets, compatible with FSF 20.3
1975      Naming convention is Script-Charset[-Edition] */
1976   defsymbol (&Qascii,                   "ascii");
1977   defsymbol (&Qcontrol_1,               "control-1");
1978   defsymbol (&Qlatin_iso8859_1,         "latin-iso8859-1");
1979   defsymbol (&Qlatin_iso8859_2,         "latin-iso8859-2");
1980   defsymbol (&Qlatin_iso8859_3,         "latin-iso8859-3");
1981   defsymbol (&Qlatin_iso8859_4,         "latin-iso8859-4");
1982   defsymbol (&Qthai_tis620,             "thai-tis620");
1983   defsymbol (&Qgreek_iso8859_7,         "greek-iso8859-7");
1984   defsymbol (&Qarabic_iso8859_6,        "arabic-iso8859-6");
1985   defsymbol (&Qhebrew_iso8859_8,        "hebrew-iso8859-8");
1986   defsymbol (&Qkatakana_jisx0201,       "katakana-jisx0201");
1987   defsymbol (&Qlatin_jisx0201,          "latin-jisx0201");
1988   defsymbol (&Qcyrillic_iso8859_5,      "cyrillic-iso8859-5");
1989   defsymbol (&Qlatin_iso8859_9,         "latin-iso8859-9");
1990   defsymbol (&Qjapanese_jisx0208_1978,  "japanese-jisx0208-1978");
1991   defsymbol (&Qchinese_gb2312,          "chinese-gb2312");
1992   defsymbol (&Qjapanese_jisx0208,       "japanese-jisx0208");
1993   defsymbol (&Qkorean_ksc5601,          "korean-ksc5601");
1994   defsymbol (&Qjapanese_jisx0212,       "japanese-jisx0212");
1995   defsymbol (&Qchinese_cns11643_1,      "chinese-cns11643-1");
1996   defsymbol (&Qchinese_cns11643_2,      "chinese-cns11643-2");
1997 #ifdef UTF2000
1998   defsymbol (&Qucs_bmp,                 "ucs-bmp");
1999   defsymbol (&Qlatin_viscii,            "latin-viscii");
2000   defsymbol (&Qlatin_viscii_lower,      "latin-viscii-lower");
2001   defsymbol (&Qlatin_viscii_upper,      "latin-viscii-upper");
2002   defsymbol (&Qvietnamese_viscii_lower, "vietnamese-viscii-lower");
2003   defsymbol (&Qvietnamese_viscii_upper, "vietnamese-viscii-upper");
2004   defsymbol (&Qhiragana_jisx0208,       "hiragana-jisx0208");
2005   defsymbol (&Qkatakana_jisx0208,       "katakana-jisx0208");
2006 #endif
2007   defsymbol (&Qchinese_big5_1,          "chinese-big5-1");
2008   defsymbol (&Qchinese_big5_2,          "chinese-big5-2");
2009
2010   defsymbol (&Qcomposite,               "composite");
2011 }
2012
2013 void
2014 vars_of_mule_charset (void)
2015 {
2016   int i, j;
2017 #ifndef UTF2000
2018   int k;
2019 #endif
2020
2021   /* Table of charsets indexed by leading byte. */
2022   for (i = 0; i < countof (charset_by_leading_byte); i++)
2023     charset_by_leading_byte[i] = Qnil;
2024
2025 #ifdef UTF2000
2026   /* Table of charsets indexed by type/final-byte. */
2027   for (i = 0; i < countof (charset_by_attributes); i++)
2028     for (j = 0; j < countof (charset_by_attributes[0]); j++)
2029         charset_by_attributes[i][j] = Qnil;
2030 #else
2031   /* Table of charsets indexed by type/final-byte/direction. */
2032   for (i = 0; i < countof (charset_by_attributes); i++)
2033     for (j = 0; j < countof (charset_by_attributes[0]); j++)
2034       for (k = 0; k < countof (charset_by_attributes[0][0]); k++)
2035         charset_by_attributes[i][j][k] = Qnil;
2036 #endif
2037
2038 #ifdef UTF2000
2039   next_allocated_leading_byte = MIN_LEADING_BYTE_PRIVATE;
2040 #else
2041   next_allocated_1_byte_leading_byte = MIN_LEADING_BYTE_PRIVATE_1;
2042   next_allocated_2_byte_leading_byte = MIN_LEADING_BYTE_PRIVATE_2;
2043 #endif
2044
2045 #ifndef UTF2000
2046   leading_code_private_11 = PRE_LEADING_BYTE_PRIVATE_1;
2047   DEFVAR_INT ("leading-code-private-11", &leading_code_private_11 /*
2048 Leading-code of private TYPE9N charset of column-width 1.
2049 */ );
2050   leading_code_private_11 = PRE_LEADING_BYTE_PRIVATE_1;
2051 #endif
2052
2053 #ifdef UTF2000
2054   Vutf_2000_version = build_string("0.10 (Yao)");
2055   DEFVAR_LISP ("utf-2000-version", &Vutf_2000_version /*
2056 Version number of UTF-2000.
2057 */ );
2058
2059   staticpro (&Vcharacter_attribute_table);
2060   Vcharacter_attribute_table = make_char_code_table (Qnil);
2061
2062   Vdefault_coded_charset_priority_list = Qnil;
2063   DEFVAR_LISP ("default-coded-charset-priority-list",
2064                &Vdefault_coded_charset_priority_list /*
2065 Default order of preferred coded-character-sets.
2066 */ );
2067 #endif
2068 }
2069
2070 void
2071 complex_vars_of_mule_charset (void)
2072 {
2073   staticpro (&Vcharset_hash_table);
2074   Vcharset_hash_table =
2075     make_lisp_hash_table (50, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
2076
2077   /* Predefined character sets.  We store them into variables for
2078      ease of access. */
2079
2080 #ifdef UTF2000
2081   Vcharset_ucs_bmp =
2082     make_charset (LEADING_BYTE_UCS_BMP, Qucs_bmp,
2083                   CHARSET_TYPE_256X256, 1, 2, 0,
2084                   CHARSET_LEFT_TO_RIGHT,
2085                   build_string ("BMP"),
2086                   build_string ("BMP"),
2087                   build_string ("ISO/IEC 10646 Group 0 Plane 0 (BMP)"),
2088                   build_string ("\\(ISO10646.*-1\\|UNICODE[23]?-0\\)"),
2089                   Qnil, 0, 0xFFFF, 0, 0);
2090 #else
2091 # define MIN_CHAR_THAI 0
2092 # define MAX_CHAR_THAI 0
2093 # define MIN_CHAR_GREEK 0
2094 # define MAX_CHAR_GREEK 0
2095 # define MIN_CHAR_HEBREW 0
2096 # define MAX_CHAR_HEBREW 0
2097 # define MIN_CHAR_HALFWIDTH_KATAKANA 0
2098 # define MAX_CHAR_HALFWIDTH_KATAKANA 0
2099 # define MIN_CHAR_CYRILLIC 0
2100 # define MAX_CHAR_CYRILLIC 0
2101 #endif
2102   Vcharset_ascii =
2103     make_charset (LEADING_BYTE_ASCII, Qascii,
2104                   CHARSET_TYPE_94, 1, 0, 'B',
2105                   CHARSET_LEFT_TO_RIGHT,
2106                   build_string ("ASCII"),
2107                   build_string ("ASCII)"),
2108                   build_string ("ASCII (ISO646 IRV)"),
2109                   build_string ("\\(iso8859-[0-9]*\\|-ascii\\)"),
2110                   Qnil, 0, 0x7F, 0, 0);
2111   Vcharset_control_1 =
2112     make_charset (LEADING_BYTE_CONTROL_1, Qcontrol_1,
2113                   CHARSET_TYPE_94, 1, 1, 0,
2114                   CHARSET_LEFT_TO_RIGHT,
2115                   build_string ("C1"),
2116                   build_string ("Control characters"),
2117                   build_string ("Control characters 128-191"),
2118                   build_string (""),
2119                   Qnil, 0x80, 0x9F, 0, 0);
2120   Vcharset_latin_iso8859_1 =
2121     make_charset (LEADING_BYTE_LATIN_ISO8859_1, Qlatin_iso8859_1,
2122                   CHARSET_TYPE_96, 1, 1, 'A',
2123                   CHARSET_LEFT_TO_RIGHT,
2124                   build_string ("Latin-1"),
2125                   build_string ("ISO8859-1 (Latin-1)"),
2126                   build_string ("ISO8859-1 (Latin-1)"),
2127                   build_string ("iso8859-1"),
2128                   Qnil, 0xA0, 0xFF, 0, 32);
2129   Vcharset_latin_iso8859_2 =
2130     make_charset (LEADING_BYTE_LATIN_ISO8859_2, Qlatin_iso8859_2,
2131                   CHARSET_TYPE_96, 1, 1, 'B',
2132                   CHARSET_LEFT_TO_RIGHT,
2133                   build_string ("Latin-2"),
2134                   build_string ("ISO8859-2 (Latin-2)"),
2135                   build_string ("ISO8859-2 (Latin-2)"),
2136                   build_string ("iso8859-2"),
2137                   Qnil, 0, 0, 0, 32);
2138   Vcharset_latin_iso8859_3 =
2139     make_charset (LEADING_BYTE_LATIN_ISO8859_3, Qlatin_iso8859_3,
2140                   CHARSET_TYPE_96, 1, 1, 'C',
2141                   CHARSET_LEFT_TO_RIGHT,
2142                   build_string ("Latin-3"),
2143                   build_string ("ISO8859-3 (Latin-3)"),
2144                   build_string ("ISO8859-3 (Latin-3)"),
2145                   build_string ("iso8859-3"),
2146                   Qnil, 0, 0, 0, 32);
2147   Vcharset_latin_iso8859_4 =
2148     make_charset (LEADING_BYTE_LATIN_ISO8859_4, Qlatin_iso8859_4,
2149                   CHARSET_TYPE_96, 1, 1, 'D',
2150                   CHARSET_LEFT_TO_RIGHT,
2151                   build_string ("Latin-4"),
2152                   build_string ("ISO8859-4 (Latin-4)"),
2153                   build_string ("ISO8859-4 (Latin-4)"),
2154                   build_string ("iso8859-4"),
2155                   Qnil, 0, 0, 0, 32);
2156   Vcharset_thai_tis620 =
2157     make_charset (LEADING_BYTE_THAI_TIS620, Qthai_tis620,
2158                   CHARSET_TYPE_96, 1, 1, 'T',
2159                   CHARSET_LEFT_TO_RIGHT,
2160                   build_string ("TIS620"),
2161                   build_string ("TIS620 (Thai)"),
2162                   build_string ("TIS620.2529 (Thai)"),
2163                   build_string ("tis620"),
2164                   Qnil, MIN_CHAR_THAI, MAX_CHAR_THAI, 0, 32);
2165   Vcharset_greek_iso8859_7 =
2166     make_charset (LEADING_BYTE_GREEK_ISO8859_7, Qgreek_iso8859_7,
2167                   CHARSET_TYPE_96, 1, 1, 'F',
2168                   CHARSET_LEFT_TO_RIGHT,
2169                   build_string ("ISO8859-7"),
2170                   build_string ("ISO8859-7 (Greek)"),
2171                   build_string ("ISO8859-7 (Greek)"),
2172                   build_string ("iso8859-7"),
2173                   Qnil, MIN_CHAR_GREEK, MAX_CHAR_GREEK, 0, 32);
2174   Vcharset_arabic_iso8859_6 =
2175     make_charset (LEADING_BYTE_ARABIC_ISO8859_6, Qarabic_iso8859_6,
2176                   CHARSET_TYPE_96, 1, 1, 'G',
2177                   CHARSET_RIGHT_TO_LEFT,
2178                   build_string ("ISO8859-6"),
2179                   build_string ("ISO8859-6 (Arabic)"),
2180                   build_string ("ISO8859-6 (Arabic)"),
2181                   build_string ("iso8859-6"),
2182                   Qnil, 0, 0, 0, 32);
2183   Vcharset_hebrew_iso8859_8 =
2184     make_charset (LEADING_BYTE_HEBREW_ISO8859_8, Qhebrew_iso8859_8,
2185                   CHARSET_TYPE_96, 1, 1, 'H',
2186                   CHARSET_RIGHT_TO_LEFT,
2187                   build_string ("ISO8859-8"),
2188                   build_string ("ISO8859-8 (Hebrew)"),
2189                   build_string ("ISO8859-8 (Hebrew)"),
2190                   build_string ("iso8859-8"),
2191                   Qnil, MIN_CHAR_HEBREW, MAX_CHAR_HEBREW, 0, 32);
2192   Vcharset_katakana_jisx0201 =
2193     make_charset (LEADING_BYTE_KATAKANA_JISX0201, Qkatakana_jisx0201,
2194                   CHARSET_TYPE_94, 1, 1, 'I',
2195                   CHARSET_LEFT_TO_RIGHT,
2196                   build_string ("JISX0201 Kana"),
2197                   build_string ("JISX0201.1976 (Japanese Kana)"),
2198                   build_string ("JISX0201.1976 Japanese Kana"),
2199                   build_string ("jisx0201\\.1976"),
2200                   Qnil,
2201                   MIN_CHAR_HALFWIDTH_KATAKANA,
2202                   MAX_CHAR_HALFWIDTH_KATAKANA, 0, 33);
2203   Vcharset_latin_jisx0201 =
2204     make_charset (LEADING_BYTE_LATIN_JISX0201, Qlatin_jisx0201,
2205                   CHARSET_TYPE_94, 1, 0, 'J',
2206                   CHARSET_LEFT_TO_RIGHT,
2207                   build_string ("JISX0201 Roman"),
2208                   build_string ("JISX0201.1976 (Japanese Roman)"),
2209                   build_string ("JISX0201.1976 Japanese Roman"),
2210                   build_string ("jisx0201\\.1976"),
2211                   Qnil, 0, 0, 0, 33);
2212   Vcharset_cyrillic_iso8859_5 =
2213     make_charset (LEADING_BYTE_CYRILLIC_ISO8859_5, Qcyrillic_iso8859_5,
2214                   CHARSET_TYPE_96, 1, 1, 'L',
2215                   CHARSET_LEFT_TO_RIGHT,
2216                   build_string ("ISO8859-5"),
2217                   build_string ("ISO8859-5 (Cyrillic)"),
2218                   build_string ("ISO8859-5 (Cyrillic)"),
2219                   build_string ("iso8859-5"),
2220                   Qnil, MIN_CHAR_CYRILLIC, MAX_CHAR_CYRILLIC, 0, 32);
2221   Vcharset_latin_iso8859_9 =
2222     make_charset (LEADING_BYTE_LATIN_ISO8859_9, Qlatin_iso8859_9,
2223                   CHARSET_TYPE_96, 1, 1, 'M',
2224                   CHARSET_LEFT_TO_RIGHT,
2225                   build_string ("Latin-5"),
2226                   build_string ("ISO8859-9 (Latin-5)"),
2227                   build_string ("ISO8859-9 (Latin-5)"),
2228                   build_string ("iso8859-9"),
2229                   Qnil, 0, 0, 0, 32);
2230   Vcharset_japanese_jisx0208_1978 =
2231     make_charset (LEADING_BYTE_JAPANESE_JISX0208_1978, Qjapanese_jisx0208_1978,
2232                   CHARSET_TYPE_94X94, 2, 0, '@',
2233                   CHARSET_LEFT_TO_RIGHT,
2234                   build_string ("JIS X0208:1978"),
2235                   build_string ("JIS X0208:1978 (Japanese)"),
2236                   build_string
2237                   ("JIS X0208:1978 Japanese Kanji (so called \"old JIS\")"),
2238                   build_string ("\\(jisx0208\\|jisc6226\\)\\.1978"),
2239                   Qnil, 0, 0, 0, 33);
2240   Vcharset_chinese_gb2312 =
2241     make_charset (LEADING_BYTE_CHINESE_GB2312, Qchinese_gb2312,
2242                   CHARSET_TYPE_94X94, 2, 0, 'A',
2243                   CHARSET_LEFT_TO_RIGHT,
2244                   build_string ("GB2312"),
2245                   build_string ("GB2312)"),
2246                   build_string ("GB2312 Chinese simplified"),
2247                   build_string ("gb2312"),
2248                   Qnil, 0, 0, 0, 33);
2249   Vcharset_japanese_jisx0208 =
2250     make_charset (LEADING_BYTE_JAPANESE_JISX0208, Qjapanese_jisx0208,
2251                   CHARSET_TYPE_94X94, 2, 0, 'B',
2252                   CHARSET_LEFT_TO_RIGHT,
2253                   build_string ("JISX0208"),
2254                   build_string ("JIS X0208:1983 (Japanese)"),
2255                   build_string ("JIS X0208:1983 Japanese Kanji"),
2256                   build_string ("jisx0208\\.1983"),
2257                   Qnil, 0, 0, 0, 33);
2258   Vcharset_korean_ksc5601 =
2259     make_charset (LEADING_BYTE_KOREAN_KSC5601, Qkorean_ksc5601,
2260                   CHARSET_TYPE_94X94, 2, 0, 'C',
2261                   CHARSET_LEFT_TO_RIGHT,
2262                   build_string ("KSC5601"),
2263                   build_string ("KSC5601 (Korean"),
2264                   build_string ("KSC5601 Korean Hangul and Hanja"),
2265                   build_string ("ksc5601"),
2266                   Qnil, 0, 0, 0, 33);
2267   Vcharset_japanese_jisx0212 =
2268     make_charset (LEADING_BYTE_JAPANESE_JISX0212, Qjapanese_jisx0212,
2269                   CHARSET_TYPE_94X94, 2, 0, 'D',
2270                   CHARSET_LEFT_TO_RIGHT,
2271                   build_string ("JISX0212"),
2272                   build_string ("JISX0212 (Japanese)"),
2273                   build_string ("JISX0212 Japanese Supplement"),
2274                   build_string ("jisx0212"),
2275                   Qnil, 0, 0, 0, 33);
2276
2277 #define CHINESE_CNS_PLANE_RE(n) "cns11643[.-]\\(.*[.-]\\)?" n "$"
2278   Vcharset_chinese_cns11643_1 =
2279     make_charset (LEADING_BYTE_CHINESE_CNS11643_1, Qchinese_cns11643_1,
2280                   CHARSET_TYPE_94X94, 2, 0, 'G',
2281                   CHARSET_LEFT_TO_RIGHT,
2282                   build_string ("CNS11643-1"),
2283                   build_string ("CNS11643-1 (Chinese traditional)"),
2284                   build_string
2285                   ("CNS 11643 Plane 1 Chinese traditional"),
2286                   build_string (CHINESE_CNS_PLANE_RE("1")),
2287                   Qnil, 0, 0, 0, 33);
2288   Vcharset_chinese_cns11643_2 =
2289     make_charset (LEADING_BYTE_CHINESE_CNS11643_2, Qchinese_cns11643_2,
2290                   CHARSET_TYPE_94X94, 2, 0, 'H',
2291                   CHARSET_LEFT_TO_RIGHT,
2292                   build_string ("CNS11643-2"),
2293                   build_string ("CNS11643-2 (Chinese traditional)"),
2294                   build_string
2295                   ("CNS 11643 Plane 2 Chinese traditional"),
2296                   build_string (CHINESE_CNS_PLANE_RE("2")),
2297                   Qnil, 0, 0, 0, 33);
2298 #ifdef UTF2000
2299   Vcharset_latin_viscii_lower =
2300     make_charset (LEADING_BYTE_LATIN_VISCII_LOWER, Qlatin_viscii_lower,
2301                   CHARSET_TYPE_96, 1, 1, '1',
2302                   CHARSET_LEFT_TO_RIGHT,
2303                   build_string ("VISCII lower"),
2304                   build_string ("VISCII lower (Vietnamese)"),
2305                   build_string ("VISCII lower (Vietnamese)"),
2306                   build_string ("MULEVISCII-LOWER"),
2307                   Qnil, 0, 0, 0, 32);
2308   Vcharset_latin_viscii_upper =
2309     make_charset (LEADING_BYTE_LATIN_VISCII_UPPER, Qlatin_viscii_upper,
2310                   CHARSET_TYPE_96, 1, 1, '2',
2311                   CHARSET_LEFT_TO_RIGHT,
2312                   build_string ("VISCII upper"),
2313                   build_string ("VISCII upper (Vietnamese)"),
2314                   build_string ("VISCII upper (Vietnamese)"),
2315                   build_string ("MULEVISCII-UPPER"),
2316                   Qnil, 0, 0, 0, 32);
2317   Vcharset_latin_viscii =
2318     make_charset (LEADING_BYTE_LATIN_VISCII, Qlatin_viscii,
2319                   CHARSET_TYPE_256, 1, 2, 0,
2320                   CHARSET_LEFT_TO_RIGHT,
2321                   build_string ("VISCII"),
2322                   build_string ("VISCII 1.1 (Vietnamese)"),
2323                   build_string ("VISCII 1.1 (Vietnamese)"),
2324                   build_string ("VISCII1\\.1"),
2325                   Qnil, 0, 0, 0, 0);
2326   Vcharset_hiragana_jisx0208 =
2327     make_charset (LEADING_BYTE_HIRAGANA_JISX0208, Qhiragana_jisx0208,
2328                   CHARSET_TYPE_94X94, 2, 0, 'B',
2329                   CHARSET_LEFT_TO_RIGHT,
2330                   build_string ("Hiragana"),
2331                   build_string ("Hiragana of JIS X0208"),
2332                   build_string ("Japanese Hiragana of JIS X0208"),
2333                   build_string ("jisx0208\\.19\\(78\\|83\\|90\\)"),
2334                   Qnil, MIN_CHAR_HIRAGANA, MAX_CHAR_HIRAGANA,
2335                   (0x24 - 33) * 94 + (0x21 - 33), 33);
2336   Vcharset_katakana_jisx0208 =
2337     make_charset (LEADING_BYTE_KATAKANA_JISX0208, Qkatakana_jisx0208,
2338                   CHARSET_TYPE_94X94, 2, 0, 'B',
2339                   CHARSET_LEFT_TO_RIGHT,
2340                   build_string ("Katakana"),
2341                   build_string ("Katakana of JIS X0208"),
2342                   build_string ("Japanese Katakana of JIS X0208"),
2343                   build_string ("jisx0208\\.19\\(78\\|83\\|90\\)"),
2344                   Qnil, MIN_CHAR_KATAKANA, MAX_CHAR_KATAKANA,
2345                   (0x25 - 33) * 94 + (0x21 - 33), 33);
2346 #endif
2347   Vcharset_chinese_big5_1 =
2348     make_charset (LEADING_BYTE_CHINESE_BIG5_1, Qchinese_big5_1,
2349                   CHARSET_TYPE_94X94, 2, 0, '0',
2350                   CHARSET_LEFT_TO_RIGHT,
2351                   build_string ("Big5"),
2352                   build_string ("Big5 (Level-1)"),
2353                   build_string
2354                   ("Big5 Level-1 Chinese traditional"),
2355                   build_string ("big5"),
2356                   Qnil, 0, 0, 0, 33);
2357   Vcharset_chinese_big5_2 =
2358     make_charset (LEADING_BYTE_CHINESE_BIG5_2, Qchinese_big5_2,
2359                   CHARSET_TYPE_94X94, 2, 0, '1',
2360                   CHARSET_LEFT_TO_RIGHT,
2361                   build_string ("Big5"),
2362                   build_string ("Big5 (Level-2)"),
2363                   build_string
2364                   ("Big5 Level-2 Chinese traditional"),
2365                   build_string ("big5"),
2366                   Qnil, 0, 0, 0, 33);
2367
2368 #ifdef ENABLE_COMPOSITE_CHARS
2369   /* #### For simplicity, we put composite chars into a 96x96 charset.
2370      This is going to lead to problems because you can run out of
2371      room, esp. as we don't yet recycle numbers. */
2372   Vcharset_composite =
2373     make_charset (LEADING_BYTE_COMPOSITE, Qcomposite,
2374                   CHARSET_TYPE_96X96, 2, 0, 0,
2375                   CHARSET_LEFT_TO_RIGHT,
2376                   build_string ("Composite"),
2377                   build_string ("Composite characters"),
2378                   build_string ("Composite characters"),
2379                   build_string (""));
2380
2381   composite_char_row_next = 32;
2382   composite_char_col_next = 32;
2383
2384   Vcomposite_char_string2char_hash_table =
2385     make_lisp_hash_table (500, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
2386   Vcomposite_char_char2string_hash_table =
2387     make_lisp_hash_table (500, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
2388   staticpro (&Vcomposite_char_string2char_hash_table);
2389   staticpro (&Vcomposite_char_char2string_hash_table);
2390 #endif /* ENABLE_COMPOSITE_CHARS */
2391
2392 }