lisp/progmodes/prog-mode.el: Force font-lock to deal with `composition' prop.
[bpt/emacs.git] / src / chartab.c
CommitLineData
1ee5d538 1/* chartab.c -- char-table support
5df4f04c 2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
1ee5d538
KH
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H13PRO009
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
1ee5d538 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
1ee5d538
KH
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1ee5d538
KH
20
21#include <config.h>
0328b6de 22
b4a12c67
DL
23#include "lisp.h"
24#include "character.h"
25#include "charset.h"
26#include "ccl.h"
1ee5d538
KH
27
28/* 64/16/32/128 */
29
30/* Number of elements in Nth level char-table. */
31const int chartab_size[4] =
32 { (1 << CHARTAB_SIZE_BITS_0),
33 (1 << CHARTAB_SIZE_BITS_1),
34 (1 << CHARTAB_SIZE_BITS_2),
35 (1 << CHARTAB_SIZE_BITS_3) };
36
37/* Number of characters each element of Nth level char-table
38 covers. */
38dfbee1 39static const int chartab_chars[4] =
1ee5d538
KH
40 { (1 << (CHARTAB_SIZE_BITS_1 + CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3)),
41 (1 << (CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3)),
42 (1 << CHARTAB_SIZE_BITS_3),
43 1 };
44
45/* Number of characters (in bits) each element of Nth level char-table
46 covers. */
38dfbee1 47static const int chartab_bits[4] =
1ee5d538
KH
48 { (CHARTAB_SIZE_BITS_1 + CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3),
49 (CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3),
50 CHARTAB_SIZE_BITS_3,
51 0 };
52
53#define CHARTAB_IDX(c, depth, min_char) \
54 (((c) - (min_char)) >> chartab_bits[(depth)])
55
c805dec0
KH
56\f
57/* Preamble for uniprop (Unicode character property) tables. See the
58 comment of "Unicode character property tables". */
59
60/* Purpose of uniprop tables. */
61static Lisp_Object Qchar_code_property_table;
62
63/* Types of decoder and encoder functions for uniprop values. */
64typedef Lisp_Object (*uniprop_decoder_t) (Lisp_Object, Lisp_Object);
65typedef Lisp_Object (*uniprop_encoder_t) (Lisp_Object, Lisp_Object);
66
67static Lisp_Object uniprop_table_uncompress (Lisp_Object, int);
68static uniprop_decoder_t uniprop_get_decoder (Lisp_Object);
69
70/* 1 iff TABLE is a uniprop table. */
71#define UNIPROP_TABLE_P(TABLE) \
72 (EQ (XCHAR_TABLE (TABLE)->purpose, Qchar_code_property_table) \
73 && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (TABLE)) == 5)
74
75/* Return a decoder for values in the uniprop table TABLE. */
76#define UNIPROP_GET_DECODER(TABLE) \
77 (UNIPROP_TABLE_P (TABLE) ? uniprop_get_decoder (TABLE) : NULL)
1ee5d538 78
c805dec0
KH
79/* Nonzero iff OBJ is a string representing uniprop values of 128
80 succeeding characters (the bottom level of a char-table) by a
81 compressed format. We are sure that no property value has a string
82 starting with '\001' nor '\002'. */
83#define UNIPROP_COMPRESSED_FORM_P(OBJ) \
84 (STRINGP (OBJ) && SCHARS (OBJ) > 0 \
85 && ((SREF (OBJ, 0) == 1 || (SREF (OBJ, 0) == 2))))
86
87\f
a7ca3326 88DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0,
eaa3b0e0 89 doc: /* Return a newly created char-table, with purpose PURPOSE.
1ee5d538
KH
90Each element is initialized to INIT, which defaults to nil.
91
eaa3b0e0
KH
92PURPOSE should be a symbol. If it has a `char-table-extra-slots'
93property, the property's value should be an integer between 0 and 10
94that specifies how many extra slots the char-table has. Otherwise,
95the char-table has no extra slot. */)
5842a27b 96 (register Lisp_Object purpose, Lisp_Object init)
1ee5d538
KH
97{
98 Lisp_Object vector;
99 Lisp_Object n;
eaa3b0e0 100 int n_extras;
1ee5d538
KH
101 int size;
102
103 CHECK_SYMBOL (purpose);
eaa3b0e0
KH
104 n = Fget (purpose, Qchar_table_extra_slots);
105 if (NILP (n))
106 n_extras = 0;
107 else
1ee5d538 108 {
eaa3b0e0 109 CHECK_NATNUM (n);
d311d28c 110 if (XINT (n) > 10)
eaa3b0e0 111 args_out_of_range (n, Qnil);
d311d28c 112 n_extras = XINT (n);
1ee5d538
KH
113 }
114
115 size = VECSIZE (struct Lisp_Char_Table) - 1 + n_extras;
116 vector = Fmake_vector (make_number (size), init);
985773c9 117 XSETPVECTYPE (XVECTOR (vector), PVEC_CHAR_TABLE);
742af32f
PE
118 set_char_table_parent (vector, Qnil);
119 set_char_table_purpose (vector, purpose);
1ee5d538
KH
120 XSETCHAR_TABLE (vector, XCHAR_TABLE (vector));
121 return vector;
122}
123
124static Lisp_Object
971de7fb 125make_sub_char_table (int depth, int min_char, Lisp_Object defalt)
1ee5d538
KH
126{
127 Lisp_Object table;
128 int size = VECSIZE (struct Lisp_Sub_Char_Table) - 1 + chartab_size[depth];
1ee5d538
KH
129
130 table = Fmake_vector (make_number (size), defalt);
985773c9 131 XSETPVECTYPE (XVECTOR (table), PVEC_SUB_CHAR_TABLE);
1ee5d538
KH
132 XSUB_CHAR_TABLE (table)->depth = make_number (depth);
133 XSUB_CHAR_TABLE (table)->min_char = make_number (min_char);
1ee5d538
KH
134
135 return table;
136}
137
138static Lisp_Object
971de7fb 139char_table_ascii (Lisp_Object table)
1ee5d538 140{
c805dec0 141 Lisp_Object sub, val;
1ee5d538
KH
142
143 sub = XCHAR_TABLE (table)->contents[0];
40033db7
KH
144 if (! SUB_CHAR_TABLE_P (sub))
145 return sub;
1ee5d538 146 sub = XSUB_CHAR_TABLE (sub)->contents[0];
40033db7
KH
147 if (! SUB_CHAR_TABLE_P (sub))
148 return sub;
c805dec0
KH
149 val = XSUB_CHAR_TABLE (sub)->contents[0];
150 if (UNIPROP_TABLE_P (table) && UNIPROP_COMPRESSED_FORM_P (val))
151 val = uniprop_table_uncompress (sub, 0);
152 return val;
1ee5d538
KH
153}
154
fb93dbc2 155static Lisp_Object
971de7fb 156copy_sub_char_table (Lisp_Object table)
1ee5d538 157{
1ee5d538
KH
158 int depth = XINT (XSUB_CHAR_TABLE (table)->depth);
159 int min_char = XINT (XSUB_CHAR_TABLE (table)->min_char);
34dabdb7 160 Lisp_Object copy = make_sub_char_table (depth, min_char, Qnil);
1ee5d538
KH
161 int i;
162
1ee5d538
KH
163 /* Recursively copy any sub char-tables. */
164 for (i = 0; i < chartab_size[depth]; i++)
165 {
34dabdb7
PE
166 Lisp_Object val = XSUB_CHAR_TABLE (table)->contents[i];
167 set_sub_char_table_contents
168 (copy, i, SUB_CHAR_TABLE_P (val) ? copy_sub_char_table (val) : val);
1ee5d538
KH
169 }
170
171 return copy;
172}
173
174
175Lisp_Object
971de7fb 176copy_char_table (Lisp_Object table)
1ee5d538
KH
177{
178 Lisp_Object copy;
eab3844f 179 int size = XCHAR_TABLE (table)->header.size & PSEUDOVECTOR_SIZE_MASK;
1ee5d538
KH
180 int i;
181
182 copy = Fmake_vector (make_number (size), Qnil);
985773c9 183 XSETPVECTYPE (XVECTOR (copy), PVEC_CHAR_TABLE);
742af32f
PE
184 set_char_table_defalt (copy, XCHAR_TABLE (table)->defalt);
185 set_char_table_parent (copy, XCHAR_TABLE (table)->parent);
186 set_char_table_purpose (copy, XCHAR_TABLE (table)->purpose);
1ee5d538 187 for (i = 0; i < chartab_size[0]; i++)
34dabdb7 188 set_char_table_contents
742af32f 189 (copy, i,
a098c930
DA
190 (SUB_CHAR_TABLE_P (XCHAR_TABLE (table)->contents[i])
191 ? copy_sub_char_table (XCHAR_TABLE (table)->contents[i])
192 : XCHAR_TABLE (table)->contents[i]));
742af32f 193 set_char_table_ascii (copy, char_table_ascii (copy));
1ee5d538
KH
194 size -= VECSIZE (struct Lisp_Char_Table) - 1;
195 for (i = 0; i < size; i++)
34dabdb7 196 set_char_table_extras (copy, i, XCHAR_TABLE (table)->extras[i]);
1ee5d538
KH
197
198 XSETCHAR_TABLE (copy, XCHAR_TABLE (copy));
199 return copy;
200}
201
2f7c71a1 202static Lisp_Object
d5172d4f 203sub_char_table_ref (Lisp_Object table, int c, bool is_uniprop)
1ee5d538
KH
204{
205 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
206 int depth = XINT (tbl->depth);
207 int min_char = XINT (tbl->min_char);
208 Lisp_Object val;
c805dec0 209 int idx = CHARTAB_IDX (c, depth, min_char);
1ee5d538 210
c805dec0
KH
211 val = tbl->contents[idx];
212 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
213 val = uniprop_table_uncompress (table, idx);
1ee5d538 214 if (SUB_CHAR_TABLE_P (val))
c805dec0 215 val = sub_char_table_ref (val, c, is_uniprop);
1ee5d538
KH
216 return val;
217}
218
219Lisp_Object
971de7fb 220char_table_ref (Lisp_Object table, int c)
1ee5d538
KH
221{
222 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
223 Lisp_Object val;
224
225 if (ASCII_CHAR_P (c))
226 {
227 val = tbl->ascii;
228 if (SUB_CHAR_TABLE_P (val))
229 val = XSUB_CHAR_TABLE (val)->contents[c];
230 }
231 else
232 {
233 val = tbl->contents[CHARTAB_IDX (c, 0, 0)];
234 if (SUB_CHAR_TABLE_P (val))
c805dec0 235 val = sub_char_table_ref (val, c, UNIPROP_TABLE_P (table));
1ee5d538
KH
236 }
237 if (NILP (val))
238 {
239 val = tbl->defalt;
240 if (NILP (val) && CHAR_TABLE_P (tbl->parent))
241 val = char_table_ref (tbl->parent, c);
242 }
243 return val;
8f924df7 244}
1ee5d538
KH
245
246static Lisp_Object
c805dec0 247sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to,
d5172d4f 248 Lisp_Object defalt, bool is_uniprop)
1ee5d538
KH
249{
250 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
251 int depth = XINT (tbl->depth);
252 int min_char = XINT (tbl->min_char);
5c156ace 253 int chartab_idx = CHARTAB_IDX (c, depth, min_char), idx;
1ee5d538 254 Lisp_Object val;
8f924df7 255
5c156ace 256 val = tbl->contents[chartab_idx];
c805dec0
KH
257 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
258 val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 259 if (SUB_CHAR_TABLE_P (val))
c805dec0 260 val = sub_char_table_ref_and_range (val, c, from, to, defalt, is_uniprop);
e15009d9
KH
261 else if (NILP (val))
262 val = defalt;
263
5c156ace 264 idx = chartab_idx;
7ef1f5d1 265 while (idx > 0 && *from < min_char + idx * chartab_chars[depth])
1ee5d538 266 {
e15009d9 267 Lisp_Object this_val;
e15009d9 268
7ef1f5d1
KH
269 c = min_char + idx * chartab_chars[depth] - 1;
270 idx--;
271 this_val = tbl->contents[idx];
c805dec0
KH
272 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
273 this_val = uniprop_table_uncompress (table, idx);
e15009d9 274 if (SUB_CHAR_TABLE_P (this_val))
c805dec0
KH
275 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt,
276 is_uniprop);
e15009d9
KH
277 else if (NILP (this_val))
278 this_val = defalt;
279
280 if (! EQ (this_val, val))
7ef1f5d1
KH
281 {
282 *from = c + 1;
283 break;
284 }
1ee5d538 285 }
fe75f926
PE
286 while (((c = (chartab_idx + 1) * chartab_chars[depth])
287 < chartab_chars[depth - 1])
288 && (c += min_char) <= *to)
1ee5d538 289 {
e15009d9 290 Lisp_Object this_val;
e15009d9 291
5c156ace
PE
292 chartab_idx++;
293 this_val = tbl->contents[chartab_idx];
c805dec0
KH
294 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
295 this_val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 296 if (SUB_CHAR_TABLE_P (this_val))
c805dec0
KH
297 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt,
298 is_uniprop);
e15009d9
KH
299 else if (NILP (this_val))
300 this_val = defalt;
301 if (! EQ (this_val, val))
7ef1f5d1
KH
302 {
303 *to = c - 1;
304 break;
305 }
1ee5d538 306 }
e15009d9 307
1ee5d538
KH
308 return val;
309}
310
311
7ef1f5d1
KH
312/* Return the value for C in char-table TABLE. Shrink the range *FROM
313 and *TO to cover characters (containing C) that have the same value
314 as C. It is not assured that the values of (*FROM - 1) and (*TO +
315 1) are different from that of C. */
e15009d9 316
1ee5d538 317Lisp_Object
971de7fb 318char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
1ee5d538
KH
319{
320 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
5c156ace 321 int chartab_idx = CHARTAB_IDX (c, 0, 0), idx;
1ee5d538 322 Lisp_Object val;
d5172d4f 323 bool is_uniprop = UNIPROP_TABLE_P (table);
1ee5d538 324
5c156ace 325 val = tbl->contents[chartab_idx];
7ef1f5d1
KH
326 if (*from < 0)
327 *from = 0;
328 if (*to < 0)
329 *to = MAX_CHAR;
c805dec0
KH
330 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
331 val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 332 if (SUB_CHAR_TABLE_P (val))
c805dec0
KH
333 val = sub_char_table_ref_and_range (val, c, from, to, tbl->defalt,
334 is_uniprop);
e15009d9
KH
335 else if (NILP (val))
336 val = tbl->defalt;
5c156ace 337 idx = chartab_idx;
7ef1f5d1 338 while (*from < idx * chartab_chars[0])
1ee5d538 339 {
e15009d9 340 Lisp_Object this_val;
e15009d9 341
7ef1f5d1
KH
342 c = idx * chartab_chars[0] - 1;
343 idx--;
344 this_val = tbl->contents[idx];
c805dec0
KH
345 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
346 this_val = uniprop_table_uncompress (table, idx);
e15009d9 347 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 348 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
c805dec0 349 tbl->defalt, is_uniprop);
e15009d9
KH
350 else if (NILP (this_val))
351 this_val = tbl->defalt;
352
353 if (! EQ (this_val, val))
7ef1f5d1
KH
354 {
355 *from = c + 1;
356 break;
357 }
1ee5d538 358 }
5c156ace 359 while (*to >= (chartab_idx + 1) * chartab_chars[0])
1ee5d538 360 {
e15009d9 361 Lisp_Object this_val;
e15009d9 362
5c156ace
PE
363 chartab_idx++;
364 c = chartab_idx * chartab_chars[0];
365 this_val = tbl->contents[chartab_idx];
c805dec0
KH
366 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
367 this_val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 368 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 369 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
c805dec0 370 tbl->defalt, is_uniprop);
e15009d9
KH
371 else if (NILP (this_val))
372 this_val = tbl->defalt;
373 if (! EQ (this_val, val))
7ef1f5d1
KH
374 {
375 *to = c - 1;
376 break;
377 }
1ee5d538
KH
378 }
379
1ee5d538 380 return val;
e15009d9 381}
1ee5d538
KH
382
383
1ee5d538 384static void
d5172d4f 385sub_char_table_set (Lisp_Object table, int c, Lisp_Object val, bool is_uniprop)
1ee5d538
KH
386{
387 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
388 int depth = XINT ((tbl)->depth);
389 int min_char = XINT ((tbl)->min_char);
390 int i = CHARTAB_IDX (c, depth, min_char);
391 Lisp_Object sub;
8f924df7 392
1ee5d538 393 if (depth == 3)
34dabdb7 394 set_sub_char_table_contents (table, i, val);
1ee5d538
KH
395 else
396 {
397 sub = tbl->contents[i];
398 if (! SUB_CHAR_TABLE_P (sub))
399 {
c805dec0
KH
400 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (sub))
401 sub = uniprop_table_uncompress (table, i);
402 else
403 {
404 sub = make_sub_char_table (depth + 1,
405 min_char + i * chartab_chars[depth],
406 sub);
34dabdb7 407 set_sub_char_table_contents (table, i, sub);
c805dec0 408 }
1ee5d538 409 }
c805dec0 410 sub_char_table_set (sub, c, val, is_uniprop);
1ee5d538
KH
411 }
412}
413
e757f1c6 414void
971de7fb 415char_table_set (Lisp_Object table, int c, Lisp_Object val)
1ee5d538
KH
416{
417 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
418
419 if (ASCII_CHAR_P (c)
420 && SUB_CHAR_TABLE_P (tbl->ascii))
34dabdb7 421 set_sub_char_table_contents (tbl->ascii, c, val);
1ee5d538
KH
422 else
423 {
424 int i = CHARTAB_IDX (c, 0, 0);
425 Lisp_Object sub;
426
427 sub = tbl->contents[i];
428 if (! SUB_CHAR_TABLE_P (sub))
429 {
430 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
34dabdb7 431 set_char_table_contents (table, i, sub);
1ee5d538 432 }
c805dec0 433 sub_char_table_set (sub, c, val, UNIPROP_TABLE_P (table));
1ee5d538 434 if (ASCII_CHAR_P (c))
742af32f 435 set_char_table_ascii (table, char_table_ascii (table));
1ee5d538 436 }
1ee5d538
KH
437}
438
439static void
c805dec0 440sub_char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val,
d5172d4f 441 bool is_uniprop)
1ee5d538 442{
c805dec0
KH
443 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
444 int depth = XINT ((tbl)->depth);
445 int min_char = XINT ((tbl)->min_char);
446 int chars_in_block = chartab_chars[depth];
447 int i, c, lim = chartab_size[depth];
448
449 if (from < min_char)
450 from = min_char;
451 i = CHARTAB_IDX (from, depth, min_char);
452 c = min_char + chars_in_block * i;
023e7b41 453 for (; i < lim; i++, c += chars_in_block)
1ee5d538 454 {
c805dec0
KH
455 if (c > to)
456 break;
457 if (from <= c && c + chars_in_block - 1 <= to)
34dabdb7 458 set_sub_char_table_contents (table, i, val);
c805dec0
KH
459 else
460 {
461 Lisp_Object sub = tbl->contents[i];
462 if (! SUB_CHAR_TABLE_P (sub))
463 {
464 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (sub))
465 sub = uniprop_table_uncompress (table, i);
466 else
467 {
468 sub = make_sub_char_table (depth + 1, c, sub);
34dabdb7 469 set_sub_char_table_contents (table, i, sub);
c805dec0
KH
470 }
471 }
472 sub_char_table_set_range (sub, from, to, val, is_uniprop);
473 }
1ee5d538
KH
474 }
475}
476
477
e757f1c6 478void
971de7fb 479char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val)
1ee5d538
KH
480{
481 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
1ee5d538
KH
482
483 if (from == to)
484 char_table_set (table, from, val);
485 else
486 {
d5172d4f 487 bool is_uniprop = UNIPROP_TABLE_P (table);
c805dec0
KH
488 int lim = CHARTAB_IDX (to, 0, 0);
489 int i, c;
490
491 for (i = CHARTAB_IDX (from, 0, 0), c = 0; i <= lim;
492 i++, c += chartab_chars[0])
493 {
494 if (c > to)
495 break;
496 if (from <= c && c + chartab_chars[0] - 1 <= to)
34dabdb7 497 set_char_table_contents (table, i, val);
c805dec0
KH
498 else
499 {
500 Lisp_Object sub = tbl->contents[i];
501 if (! SUB_CHAR_TABLE_P (sub))
502 {
503 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
34dabdb7 504 set_char_table_contents (table, i, sub);
c805dec0
KH
505 }
506 sub_char_table_set_range (sub, from, to, val, is_uniprop);
507 }
508 }
1ee5d538 509 if (ASCII_CHAR_P (from))
742af32f 510 set_char_table_ascii (table, char_table_ascii (table));
1ee5d538 511 }
1ee5d538
KH
512}
513
514\f
515DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
516 1, 1, 0,
517 doc: /*
518Return the subtype of char-table CHAR-TABLE. The value is a symbol. */)
5842a27b 519 (Lisp_Object char_table)
1ee5d538
KH
520{
521 CHECK_CHAR_TABLE (char_table);
522
523 return XCHAR_TABLE (char_table)->purpose;
524}
525
526DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
527 1, 1, 0,
528 doc: /* Return the parent char-table of CHAR-TABLE.
529The value is either nil or another char-table.
530If CHAR-TABLE holds nil for a given character,
531then the actual applicable value is inherited from the parent char-table
532\(or from its parents, if necessary). */)
5842a27b 533 (Lisp_Object char_table)
1ee5d538
KH
534{
535 CHECK_CHAR_TABLE (char_table);
536
537 return XCHAR_TABLE (char_table)->parent;
538}
539
a7ca3326 540DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
1ee5d538
KH
541 2, 2, 0,
542 doc: /* Set the parent char-table of CHAR-TABLE to PARENT.
6b61353c 543Return PARENT. PARENT must be either nil or another char-table. */)
5842a27b 544 (Lisp_Object char_table, Lisp_Object parent)
1ee5d538
KH
545{
546 Lisp_Object temp;
547
548 CHECK_CHAR_TABLE (char_table);
549
550 if (!NILP (parent))
551 {
552 CHECK_CHAR_TABLE (parent);
553
554 for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
555 if (EQ (temp, char_table))
556 error ("Attempt to make a chartable be its own parent");
557 }
558
742af32f 559 set_char_table_parent (char_table, parent);
1ee5d538
KH
560
561 return parent;
562}
563
a7ca3326 564DEFUN ("char-table-extra-slot", Fchar_table_extra_slot, Schar_table_extra_slot,
1ee5d538
KH
565 2, 2, 0,
566 doc: /* Return the value of CHAR-TABLE's extra-slot number N. */)
5842a27b 567 (Lisp_Object char_table, Lisp_Object n)
1ee5d538
KH
568{
569 CHECK_CHAR_TABLE (char_table);
570 CHECK_NUMBER (n);
571 if (XINT (n) < 0
572 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
573 args_out_of_range (char_table, n);
574
575 return XCHAR_TABLE (char_table)->extras[XINT (n)];
576}
577
a7ca3326 578DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
1ee5d538
KH
579 Sset_char_table_extra_slot,
580 3, 3, 0,
581 doc: /* Set CHAR-TABLE's extra-slot number N to VALUE. */)
5842a27b 582 (Lisp_Object char_table, Lisp_Object n, Lisp_Object value)
1ee5d538
KH
583{
584 CHECK_CHAR_TABLE (char_table);
585 CHECK_NUMBER (n);
586 if (XINT (n) < 0
587 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
588 args_out_of_range (char_table, n);
589
34dabdb7 590 set_char_table_extras (char_table, XINT (n), value);
a098c930 591 return value;
1ee5d538
KH
592}
593\f
594DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
595 2, 2, 0,
596 doc: /* Return the value in CHAR-TABLE for a range of characters RANGE.
597RANGE should be nil (for the default value),
598a cons of character codes (for characters in the range), or a character code. */)
5842a27b 599 (Lisp_Object char_table, Lisp_Object range)
1ee5d538
KH
600{
601 Lisp_Object val;
602 CHECK_CHAR_TABLE (char_table);
603
604 if (EQ (range, Qnil))
605 val = XCHAR_TABLE (char_table)->defalt;
8fd02eb7
PE
606 else if (CHARACTERP (range))
607 val = CHAR_TABLE_REF (char_table, XFASTINT (range));
1ee5d538
KH
608 else if (CONSP (range))
609 {
610 int from, to;
611
8f924df7
KH
612 CHECK_CHARACTER_CAR (range);
613 CHECK_CHARACTER_CDR (range);
c805dec0
KH
614 from = XFASTINT (XCAR (range));
615 to = XFASTINT (XCDR (range));
616 val = char_table_ref_and_range (char_table, from, &from, &to);
1ee5d538
KH
617 /* Not yet implemented. */
618 }
619 else
620 error ("Invalid RANGE argument to `char-table-range'");
621 return val;
622}
623
a7ca3326 624DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
1ee5d538 625 3, 3, 0,
6b61353c 626 doc: /* Set the value in CHAR-TABLE for a range of characters RANGE to VALUE.
1ee5d538 627RANGE should be t (for all characters), nil (for the default value),
6b61353c
KH
628a cons of character codes (for characters in the range),
629or a character code. Return VALUE. */)
5842a27b 630 (Lisp_Object char_table, Lisp_Object range, Lisp_Object value)
1ee5d538
KH
631{
632 CHECK_CHAR_TABLE (char_table);
633 if (EQ (range, Qt))
634 {
635 int i;
636
742af32f 637 set_char_table_ascii (char_table, value);
1ee5d538 638 for (i = 0; i < chartab_size[0]; i++)
34dabdb7 639 set_char_table_contents (char_table, i, value);
1ee5d538
KH
640 }
641 else if (EQ (range, Qnil))
742af32f 642 set_char_table_defalt (char_table, value);
d311d28c 643 else if (CHARACTERP (range))
1ee5d538
KH
644 char_table_set (char_table, XINT (range), value);
645 else if (CONSP (range))
646 {
8f924df7
KH
647 CHECK_CHARACTER_CAR (range);
648 CHECK_CHARACTER_CDR (range);
1ee5d538
KH
649 char_table_set_range (char_table,
650 XINT (XCAR (range)), XINT (XCDR (range)), value);
651 }
652 else
653 error ("Invalid RANGE argument to `set-char-table-range'");
654
655 return value;
656}
657
1ee5d538 658/* Look up the element in TABLE at index CH, and return it as an
05d6275c 659 integer. If the element is not a character, return CH itself. */
1ee5d538
KH
660
661int
971de7fb 662char_table_translate (Lisp_Object table, int ch)
1ee5d538
KH
663{
664 Lisp_Object value;
665 value = Faref (table, make_number (ch));
05d6275c 666 if (! CHARACTERP (value))
1ee5d538
KH
667 return ch;
668 return XINT (value);
669}
670
671static Lisp_Object
971de7fb 672optimize_sub_char_table (Lisp_Object table, Lisp_Object test)
1ee5d538
KH
673{
674 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
675 int depth = XINT (tbl->depth);
676 Lisp_Object elt, this;
d5172d4f
PE
677 int i;
678 bool optimizable;
1ee5d538
KH
679
680 elt = XSUB_CHAR_TABLE (table)->contents[0];
681 if (SUB_CHAR_TABLE_P (elt))
2751c80f
DA
682 {
683 elt = optimize_sub_char_table (elt, test);
34dabdb7 684 set_sub_char_table_contents (table, 0, elt);
2751c80f 685 }
c3b57f23 686 optimizable = SUB_CHAR_TABLE_P (elt) ? 0 : 1;
1ee5d538
KH
687 for (i = 1; i < chartab_size[depth]; i++)
688 {
689 this = XSUB_CHAR_TABLE (table)->contents[i];
690 if (SUB_CHAR_TABLE_P (this))
2751c80f
DA
691 {
692 this = optimize_sub_char_table (this, test);
34dabdb7 693 set_sub_char_table_contents (table, i, this);
2751c80f 694 }
c3b57f23
KH
695 if (optimizable
696 && (NILP (test) ? NILP (Fequal (this, elt)) /* defaults to `equal'. */
d0827857
SM
697 : EQ (test, Qeq) ? !EQ (this, elt) /* Optimize `eq' case. */
698 : NILP (call2 (test, this, elt))))
c3b57f23 699 optimizable = 0;
1ee5d538
KH
700 }
701
c3b57f23 702 return (optimizable ? elt : table);
1ee5d538
KH
703}
704
a7ca3326 705DEFUN ("optimize-char-table", Foptimize_char_table, Soptimize_char_table,
d0827857
SM
706 1, 2, 0,
707 doc: /* Optimize CHAR-TABLE.
708TEST is the comparison function used to decide whether two entries are
709equivalent and can be merged. It defaults to `equal'. */)
5842a27b 710 (Lisp_Object char_table, Lisp_Object test)
1ee5d538
KH
711{
712 Lisp_Object elt;
713 int i;
714
715 CHECK_CHAR_TABLE (char_table);
716
717 for (i = 0; i < chartab_size[0]; i++)
718 {
719 elt = XCHAR_TABLE (char_table)->contents[i];
720 if (SUB_CHAR_TABLE_P (elt))
34dabdb7 721 set_char_table_contents
a098c930 722 (char_table, i, optimize_sub_char_table (elt, test));
1ee5d538 723 }
4d632321 724 /* Reset the `ascii' cache, in case it got optimized away. */
742af32f 725 set_char_table_ascii (char_table, char_table_ascii (char_table));
4d632321 726
1ee5d538
KH
727 return Qnil;
728}
729
730\f
57d53d1b
KH
731/* Map C_FUNCTION or FUNCTION over TABLE (top or sub char-table),
732 calling it for each character or group of characters that share a
733 value. RANGE is a cons (FROM . TO) specifying the range of target
c805dec0 734 characters, VAL is a value of FROM in TABLE, TOP is the top
57d53d1b
KH
735 char-table.
736
737 ARG is passed to C_FUNCTION when that is called.
738
739 It returns the value of last character covered by TABLE (not the
53964682 740 value inherited from the parent), and by side-effect, the car part
57d53d1b
KH
741 of RANGE is updated to the minimum character C where C and all the
742 following characters in TABLE have the same value. */
743
1ee5d538 744static Lisp_Object
dd4c5104
DN
745map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
746 Lisp_Object function, Lisp_Object table, Lisp_Object arg, Lisp_Object val,
c805dec0 747 Lisp_Object range, Lisp_Object top)
1ee5d538 748{
57d53d1b
KH
749 /* Depth of TABLE. */
750 int depth;
0b381c7e 751 /* Minimum and maximum characters covered by TABLE. */
57d53d1b
KH
752 int min_char, max_char;
753 /* Number of characters covered by one element of TABLE. */
754 int chars_in_block;
755 int from = XINT (XCAR (range)), to = XINT (XCDR (range));
1ee5d538 756 int i, c;
d5172d4f 757 bool is_uniprop = UNIPROP_TABLE_P (top);
c805dec0 758 uniprop_decoder_t decoder = UNIPROP_GET_DECODER (top);
1ee5d538 759
57d53d1b
KH
760 if (SUB_CHAR_TABLE_P (table))
761 {
762 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
763
764 depth = XINT (tbl->depth);
57d53d1b
KH
765 min_char = XINT (tbl->min_char);
766 max_char = min_char + chartab_chars[depth - 1] - 1;
767 }
768 else
769 {
770 depth = 0;
57d53d1b
KH
771 min_char = 0;
772 max_char = MAX_CHAR;
773 }
774 chars_in_block = chartab_chars[depth];
775
776 if (to < max_char)
777 max_char = to;
778 /* Set I to the index of the first element to check. */
779 if (from <= min_char)
780 i = 0;
781 else
782 i = (from - min_char) / chars_in_block;
783 for (c = min_char + chars_in_block * i; c <= max_char;
784 i++, c += chars_in_block)
1ee5d538 785 {
c805dec0
KH
786 Lisp_Object this = (SUB_CHAR_TABLE_P (table)
787 ? XSUB_CHAR_TABLE (table)->contents[i]
788 : XCHAR_TABLE (table)->contents[i]);
57d53d1b 789 int nextc = c + chars_in_block;
1ee5d538 790
c805dec0
KH
791 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this))
792 this = uniprop_table_uncompress (table, i);
1ee5d538 793 if (SUB_CHAR_TABLE_P (this))
57d53d1b
KH
794 {
795 if (to >= nextc)
796 XSETCDR (range, make_number (nextc - 1));
797 val = map_sub_char_table (c_function, function, this, arg,
c805dec0 798 val, range, top);
57d53d1b 799 }
2f76e15e 800 else
1ee5d538 801 {
2f76e15e 802 if (NILP (this))
c805dec0 803 this = XCHAR_TABLE (top)->defalt;
d0827857 804 if (!EQ (val, this))
1ee5d538 805 {
d5172d4f 806 bool different_value = 1;
57d53d1b
KH
807
808 if (NILP (val))
809 {
c805dec0 810 if (! NILP (XCHAR_TABLE (top)->parent))
57d53d1b 811 {
c805dec0 812 Lisp_Object parent = XCHAR_TABLE (top)->parent;
57d53d1b
KH
813 Lisp_Object temp = XCHAR_TABLE (parent)->parent;
814
815 /* This is to get a value of FROM in PARENT
816 without checking the parent of PARENT. */
742af32f 817 set_char_table_parent (parent, Qnil);
57d53d1b 818 val = CHAR_TABLE_REF (parent, from);
742af32f 819 set_char_table_parent (parent, temp);
57d53d1b
KH
820 XSETCDR (range, make_number (c - 1));
821 val = map_sub_char_table (c_function, function,
822 parent, arg, val, range,
c805dec0 823 parent);
d0827857 824 if (EQ (val, this))
57d53d1b
KH
825 different_value = 0;
826 }
827 }
828 if (! NILP (val) && different_value)
1ee5d538 829 {
8f924df7 830 XSETCDR (range, make_number (c - 1));
0a4bacdc 831 if (EQ (XCAR (range), XCDR (range)))
2f76e15e
KH
832 {
833 if (c_function)
834 (*c_function) (arg, XCAR (range), val);
835 else
c805dec0
KH
836 {
837 if (decoder)
838 val = decoder (top, val);
839 call2 (function, XCAR (range), val);
840 }
2f76e15e 841 }
1ee5d538 842 else
2f76e15e
KH
843 {
844 if (c_function)
845 (*c_function) (arg, range, val);
846 else
c805dec0
KH
847 {
848 if (decoder)
849 val = decoder (top, val);
850 call2 (function, range, val);
851 }
2f76e15e 852 }
1ee5d538 853 }
2f76e15e 854 val = this;
57d53d1b 855 from = c;
8f924df7 856 XSETCAR (range, make_number (c));
1ee5d538 857 }
1ee5d538 858 }
57d53d1b 859 XSETCDR (range, make_number (to));
1ee5d538
KH
860 }
861 return val;
862}
863
864
865/* Map C_FUNCTION or FUNCTION over TABLE, calling it for each
866 character or group of characters that share a value.
867
8f924df7 868 ARG is passed to C_FUNCTION when that is called. */
1ee5d538
KH
869
870void
c805dec0
KH
871map_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
872 Lisp_Object function, Lisp_Object table, Lisp_Object arg)
1ee5d538 873{
c805dec0
KH
874 Lisp_Object range, val, parent;
875 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
876 uniprop_decoder_t decoder = UNIPROP_GET_DECODER (table);
1ee5d538 877
57d53d1b 878 range = Fcons (make_number (0), make_number (MAX_CHAR));
c805dec0
KH
879 parent = XCHAR_TABLE (table)->parent;
880
881 GCPRO4 (table, arg, range, parent);
2f76e15e
KH
882 val = XCHAR_TABLE (table)->ascii;
883 if (SUB_CHAR_TABLE_P (val))
884 val = XSUB_CHAR_TABLE (val)->contents[0];
57d53d1b 885 val = map_sub_char_table (c_function, function, table, arg, val, range,
c805dec0
KH
886 table);
887
57d53d1b
KH
888 /* If VAL is nil and TABLE has a parent, we must consult the parent
889 recursively. */
890 while (NILP (val) && ! NILP (XCHAR_TABLE (table)->parent))
1ee5d538 891 {
c805dec0 892 Lisp_Object temp;
57d53d1b
KH
893 int from = XINT (XCAR (range));
894
c805dec0
KH
895 parent = XCHAR_TABLE (table)->parent;
896 temp = XCHAR_TABLE (parent)->parent;
57d53d1b
KH
897 /* This is to get a value of FROM in PARENT without checking the
898 parent of PARENT. */
742af32f 899 set_char_table_parent (parent, Qnil);
57d53d1b 900 val = CHAR_TABLE_REF (parent, from);
742af32f 901 set_char_table_parent (parent, temp);
57d53d1b 902 val = map_sub_char_table (c_function, function, parent, arg, val, range,
c805dec0 903 parent);
57d53d1b 904 table = parent;
1ee5d538 905 }
2f76e15e
KH
906
907 if (! NILP (val))
908 {
0a4bacdc
KH
909 if (EQ (XCAR (range), XCDR (range)))
910 {
911 if (c_function)
912 (*c_function) (arg, XCAR (range), val);
913 else
c805dec0
KH
914 {
915 if (decoder)
916 val = decoder (table, val);
917 call2 (function, XCAR (range), val);
918 }
0a4bacdc 919 }
2f76e15e 920 else
0a4bacdc
KH
921 {
922 if (c_function)
923 (*c_function) (arg, range, val);
924 else
c805dec0
KH
925 {
926 if (decoder)
927 val = decoder (table, val);
928 call2 (function, range, val);
929 }
0a4bacdc 930 }
2f76e15e 931 }
26132fb5
AS
932
933 UNGCPRO;
1ee5d538
KH
934}
935
936DEFUN ("map-char-table", Fmap_char_table, Smap_char_table,
937 2, 2, 0,
55802e4a
CY
938 doc: /* Call FUNCTION for each character in CHAR-TABLE that has non-nil value.
939FUNCTION is called with two arguments, KEY and VALUE.
940KEY is a character code or a cons of character codes specifying a
941range of characters that have the same value.
942VALUE is what (char-table-range CHAR-TABLE KEY) returns. */)
5842a27b 943 (Lisp_Object function, Lisp_Object char_table)
1ee5d538
KH
944{
945 CHECK_CHAR_TABLE (char_table);
946
8f924df7 947 map_char_table (NULL, function, char_table, char_table);
1ee5d538
KH
948 return Qnil;
949}
950
e15009d9
KH
951
952static void
dd4c5104
DN
953map_sub_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Object),
954 Lisp_Object function, Lisp_Object table, Lisp_Object arg,
955 Lisp_Object range, struct charset *charset,
956 unsigned from, unsigned to)
e15009d9
KH
957{
958 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
959 int depth = XINT (tbl->depth);
960 int c, i;
961
962 if (depth < 3)
963 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth];
964 i++, c += chartab_chars[depth])
965 {
966 Lisp_Object this;
967
968 this = tbl->contents[i];
969 if (SUB_CHAR_TABLE_P (this))
970 map_sub_char_table_for_charset (c_function, function, this, arg,
971 range, charset, from, to);
972 else
973 {
974 if (! NILP (XCAR (range)))
975 {
976 XSETCDR (range, make_number (c - 1));
977 if (c_function)
978 (*c_function) (arg, range);
979 else
980 call2 (function, range, arg);
981 }
982 XSETCAR (range, Qnil);
983 }
984 }
985 else
986 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth]; i++, c ++)
987 {
988 Lisp_Object this;
989 unsigned code;
990
991 this = tbl->contents[i];
992 if (NILP (this)
993 || (charset
994 && (code = ENCODE_CHAR (charset, c),
995 (code < from || code > to))))
996 {
997 if (! NILP (XCAR (range)))
998 {
999 XSETCDR (range, make_number (c - 1));
1000 if (c_function)
bc85ac78 1001 (*c_function) (arg, range);
e15009d9
KH
1002 else
1003 call2 (function, range, arg);
1004 XSETCAR (range, Qnil);
1005 }
1006 }
1007 else
1008 {
1009 if (NILP (XCAR (range)))
1010 XSETCAR (range, make_number (c));
1011 }
1012 }
1013}
1014
1015
a6805333 1016/* Support function for `map-charset-chars'. Map C_FUNCTION or
60612c8f 1017 FUNCTION over TABLE, calling it for each character or a group of
a6805333
KH
1018 succeeding characters that have non-nil value in TABLE. TABLE is a
1019 "mapping table" or a "deunifier table" of a certain charset.
1020
1021 If CHARSET is not NULL (this is the case that `map-charset-chars'
1022 is called with non-nil FROM-CODE and TO-CODE), it is a charset who
1023 owns TABLE, and the function is called only on a character in the
1024 range FROM and TO. FROM and TO are not character codes, but code
1025 points of a character in CHARSET.
1026
1027 This function is called in these two cases:
1028
1029 (1) A charset has a mapping file name in :map property.
1030
1031 (2) A charset has an upper code space in :offset property and a
1032 mapping file name in :unify-map property. In this case, this
1033 function is called only for characters in the Unicode code space.
1034 Characters in upper code space are handled directly in
1035 map_charset_chars. */
1036
e15009d9 1037void
fb93dbc2 1038map_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Object),
dd4c5104
DN
1039 Lisp_Object function, Lisp_Object table, Lisp_Object arg,
1040 struct charset *charset,
1041 unsigned from, unsigned to)
e15009d9
KH
1042{
1043 Lisp_Object range;
1044 int c, i;
26132fb5 1045 struct gcpro gcpro1;
e15009d9 1046
8f924df7 1047 range = Fcons (Qnil, Qnil);
26132fb5 1048 GCPRO1 (range);
e15009d9
KH
1049
1050 for (i = 0, c = 0; i < chartab_size[0]; i++, c += chartab_chars[0])
1051 {
1052 Lisp_Object this;
1053
1054 this = XCHAR_TABLE (table)->contents[i];
1055 if (SUB_CHAR_TABLE_P (this))
1056 map_sub_char_table_for_charset (c_function, function, this, arg,
1057 range, charset, from, to);
1058 else
1059 {
1060 if (! NILP (XCAR (range)))
1061 {
1062 XSETCDR (range, make_number (c - 1));
1063 if (c_function)
1064 (*c_function) (arg, range);
1065 else
1066 call2 (function, range, arg);
1067 }
1068 XSETCAR (range, Qnil);
1069 }
1070 }
1071 if (! NILP (XCAR (range)))
1072 {
1073 XSETCDR (range, make_number (c - 1));
1074 if (c_function)
1075 (*c_function) (arg, range);
1076 else
1077 call2 (function, range, arg);
1078 }
26132fb5
AS
1079
1080 UNGCPRO;
e15009d9
KH
1081}
1082
1ee5d538 1083\f
c805dec0
KH
1084/* Unicode character property tables.
1085
474a8465
EZ
1086 This section provides a convenient and efficient way to get Unicode
1087 character properties of characters from C code (from Lisp, you must
1088 use get-char-code-property).
c805dec0 1089
474a8465
EZ
1090 The typical usage is to get a char-table object for a specific
1091 property like this (use of the "bidi-class" property below is just
1092 an example):
c805dec0
KH
1093
1094 Lisp_Object bidi_class_table = uniprop_table (intern ("bidi-class"));
1095
474a8465
EZ
1096 (uniprop_table can return nil if it fails to find data for the
1097 named property, or if it fails to load the appropriate Lisp support
1098 file, so the return value should be tested to be non-nil, before it
1099 is used.)
c805dec0 1100
474a8465
EZ
1101 To get a property value for character CH use CHAR_TABLE_REF:
1102
1103 Lisp_Object bidi_class = CHAR_TABLE_REF (bidi_class_table, CH);
c805dec0
KH
1104
1105 In this case, what you actually get is an index number to the
1106 vector of property values (symbols nil, L, R, etc).
1107
474a8465
EZ
1108 The full list of Unicode character properties supported by Emacs is
1109 documented in the ELisp manual, in the node "Character Properties".
1110
c805dec0
KH
1111 A table for Unicode character property has these characteristics:
1112
1113 o The purpose is `char-code-property-table', which implies that the
1114 table has 5 extra slots.
1115
1116 o The second extra slot is a Lisp function, an index (integer) to
1117 the array uniprop_decoder[], or nil. If it is a Lisp function, we
1118 can't use such a table from C (at the moment). If it is nil, it
1119 means that we don't have to decode values.
1120
1121 o The third extra slot is a Lisp function, an index (integer) to
474a8465 1122 the array uniprop_encoder[], or nil. If it is a Lisp function, we
c805dec0
KH
1123 can't use such a table from C (at the moment). If it is nil, it
1124 means that we don't have to encode values. */
1125
1126
1127/* Uncompress the IDXth element of sub-char-table TABLE. */
1128
1129static Lisp_Object
1130uniprop_table_uncompress (Lisp_Object table, int idx)
1131{
1132 Lisp_Object val = XSUB_CHAR_TABLE (table)->contents[idx];
1133 int min_char = (XINT (XSUB_CHAR_TABLE (table)->min_char)
1134 + chartab_chars[2] * idx);
1135 Lisp_Object sub = make_sub_char_table (3, min_char, Qnil);
c805dec0 1136 const unsigned char *p, *pend;
c805dec0 1137
34dabdb7 1138 set_sub_char_table_contents (table, idx, sub);
c805dec0
KH
1139 p = SDATA (val), pend = p + SBYTES (val);
1140 if (*p == 1)
1141 {
1142 /* SIMPLE TABLE */
1143 p++;
1144 idx = STRING_CHAR_ADVANCE (p);
1145 while (p < pend && idx < chartab_chars[2])
1146 {
1147 int v = STRING_CHAR_ADVANCE (p);
34dabdb7 1148 set_sub_char_table_contents
a098c930 1149 (sub, idx++, v > 0 ? make_number (v) : Qnil);
c805dec0
KH
1150 }
1151 }
1152 else if (*p == 2)
1153 {
1154 /* RUN-LENGTH TABLE */
1155 p++;
1156 for (idx = 0; p < pend; )
1157 {
1158 int v = STRING_CHAR_ADVANCE (p);
1159 int count = 1;
1160 int len;
1161
1162 if (p < pend)
1163 {
1164 count = STRING_CHAR_AND_LENGTH (p, len);
1165 if (count < 128)
1166 count = 1;
1167 else
1168 {
1169 count -= 128;
1170 p += len;
1171 }
1172 }
1173 while (count-- > 0)
34dabdb7 1174 set_sub_char_table_contents (sub, idx++, make_number (v));
c805dec0
KH
1175 }
1176 }
1177/* It seems that we don't need this function because C code won't need
1178 to get a property that is compressed in this form. */
1179#if 0
1180 else if (*p == 0)
1181 {
1182 /* WORD-LIST TABLE */
1183 }
1184#endif
1185 return sub;
1186}
1187
1188
4c36be58 1189/* Decode VALUE as an element of char-table TABLE. */
c805dec0
KH
1190
1191static Lisp_Object
1192uniprop_decode_value_run_length (Lisp_Object table, Lisp_Object value)
1193{
1194 if (VECTORP (XCHAR_TABLE (table)->extras[4]))
1195 {
1196 Lisp_Object valvec = XCHAR_TABLE (table)->extras[4];
1197
1198 if (XINT (value) >= 0 && XINT (value) < ASIZE (valvec))
1199 value = AREF (valvec, XINT (value));
1200 }
1201 return value;
1202}
1203
1204static uniprop_decoder_t uniprop_decoder [] =
1205 { uniprop_decode_value_run_length };
1206
1207static int uniprop_decoder_count
1208 = (sizeof uniprop_decoder) / sizeof (uniprop_decoder[0]);
1209
1210
1211/* Return the decoder of char-table TABLE or nil if none. */
1212
1213static uniprop_decoder_t
1214uniprop_get_decoder (Lisp_Object table)
1215{
d311d28c 1216 EMACS_INT i;
c805dec0
KH
1217
1218 if (! INTEGERP (XCHAR_TABLE (table)->extras[1]))
1219 return NULL;
1220 i = XINT (XCHAR_TABLE (table)->extras[1]);
1221 if (i < 0 || i >= uniprop_decoder_count)
1222 return NULL;
1223 return uniprop_decoder[i];
1224}
1225
1226
1227/* Encode VALUE as an element of char-table TABLE which contains
1228 characters as elements. */
1229
1230static Lisp_Object
1231uniprop_encode_value_character (Lisp_Object table, Lisp_Object value)
1232{
1233 if (! NILP (value) && ! CHARACTERP (value))
1234 wrong_type_argument (Qintegerp, value);
1235 return value;
1236}
1237
1238
1239/* Encode VALUE as an element of char-table TABLE which adopts RUN-LENGTH
1240 compression. */
1241
1242static Lisp_Object
1243uniprop_encode_value_run_length (Lisp_Object table, Lisp_Object value)
1244{
1245 Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
1246 int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
1247
1248 for (i = 0; i < size; i++)
1249 if (EQ (value, value_table[i]))
1250 break;
1251 if (i == size)
1252 wrong_type_argument (build_string ("Unicode property value"), value);
1253 return make_number (i);
1254}
1255
1256
1257/* Encode VALUE as an element of char-table TABLE which adopts RUN-LENGTH
1258 compression and contains numbers as elements . */
1259
1260static Lisp_Object
1261uniprop_encode_value_numeric (Lisp_Object table, Lisp_Object value)
1262{
1263 Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
1264 int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
1265
1266 CHECK_NUMBER (value);
1267 for (i = 0; i < size; i++)
1268 if (EQ (value, value_table[i]))
1269 break;
1270 value = make_number (i);
1271 if (i == size)
1272 {
1273 Lisp_Object args[2];
1274
1275 args[0] = XCHAR_TABLE (table)->extras[4];
1276 args[1] = Fmake_vector (make_number (1), value);
34dabdb7 1277 set_char_table_extras (table, 4, Fvconcat (2, args));
c805dec0
KH
1278 }
1279 return make_number (i);
1280}
1281
1282static uniprop_encoder_t uniprop_encoder[] =
1283 { uniprop_encode_value_character,
1284 uniprop_encode_value_run_length,
1285 uniprop_encode_value_numeric };
1286
1287static int uniprop_encoder_count
1288 = (sizeof uniprop_encoder) / sizeof (uniprop_encoder[0]);
1289
1290
1291/* Return the encoder of char-table TABLE or nil if none. */
1292
1293static uniprop_decoder_t
1294uniprop_get_encoder (Lisp_Object table)
1295{
d311d28c 1296 EMACS_INT i;
c805dec0
KH
1297
1298 if (! INTEGERP (XCHAR_TABLE (table)->extras[2]))
1299 return NULL;
1300 i = XINT (XCHAR_TABLE (table)->extras[2]);
1301 if (i < 0 || i >= uniprop_encoder_count)
1302 return NULL;
1303 return uniprop_encoder[i];
1304}
1305
1306/* Return a char-table for Unicode character property PROP. This
1307 function may load a Lisp file and thus may cause
1308 garbage-collection. */
1309
9a70f03d 1310Lisp_Object
c805dec0
KH
1311uniprop_table (Lisp_Object prop)
1312{
1313 Lisp_Object val, table, result;
1314
1315 val = Fassq (prop, Vchar_code_property_alist);
1316 if (! CONSP (val))
1317 return Qnil;
1318 table = XCDR (val);
1319 if (STRINGP (table))
1320 {
1321 struct gcpro gcpro1;
1322 GCPRO1 (val);
1323 result = Fload (concat2 (build_string ("international/"), table),
1324 Qt, Qt, Qt, Qt);
1325 UNGCPRO;
1326 if (NILP (result))
1327 return Qnil;
1328 table = XCDR (val);
1329 }
1330 if (! CHAR_TABLE_P (table)
1331 || ! UNIPROP_TABLE_P (table))
1332 return Qnil;
1333 val = XCHAR_TABLE (table)->extras[1];
1334 if (INTEGERP (val)
1335 ? (XINT (val) < 0 || XINT (val) >= uniprop_decoder_count)
1336 : ! NILP (val))
1337 return Qnil;
1338 /* Prepare ASCII values in advance for CHAR_TABLE_REF. */
742af32f 1339 set_char_table_ascii (table, char_table_ascii (table));
c805dec0
KH
1340 return table;
1341}
1342
1343DEFUN ("unicode-property-table-internal", Funicode_property_table_internal,
1344 Sunicode_property_table_internal, 1, 1, 0,
1345 doc: /* Return a char-table for Unicode character property PROP.
1346Use `get-unicode-property-internal' and
1347`put-unicode-property-internal' instead of `aref' and `aset' to get
1348and put an element value. */)
1349 (Lisp_Object prop)
1350{
1351 Lisp_Object table = uniprop_table (prop);
1352
1353 if (CHAR_TABLE_P (table))
1354 return table;
1355 return Fcdr (Fassq (prop, Vchar_code_property_alist));
1356}
1357
1358DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal,
1359 Sget_unicode_property_internal, 2, 2, 0,
1360 doc: /* Return an element of CHAR-TABLE for character CH.
1361CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1362 (Lisp_Object char_table, Lisp_Object ch)
1363{
1364 Lisp_Object val;
1365 uniprop_decoder_t decoder;
1366
1367 CHECK_CHAR_TABLE (char_table);
1368 CHECK_CHARACTER (ch);
1369 if (! UNIPROP_TABLE_P (char_table))
1370 error ("Invalid Unicode property table");
1371 val = CHAR_TABLE_REF (char_table, XINT (ch));
1372 decoder = uniprop_get_decoder (char_table);
1373 return (decoder ? decoder (char_table, val) : val);
1374}
1375
1376DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal,
1377 Sput_unicode_property_internal, 3, 3, 0,
1378 doc: /* Set an element of CHAR-TABLE for character CH to VALUE.
1379CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1380 (Lisp_Object char_table, Lisp_Object ch, Lisp_Object value)
1381{
1382 uniprop_encoder_t encoder;
1383
1384 CHECK_CHAR_TABLE (char_table);
1385 CHECK_CHARACTER (ch);
1386 if (! UNIPROP_TABLE_P (char_table))
1387 error ("Invalid Unicode property table");
1388 encoder = uniprop_get_encoder (char_table);
1389 if (encoder)
1390 value = encoder (char_table, value);
1391 CHAR_TABLE_SET (char_table, XINT (ch), value);
1392 return Qnil;
1393}
1394
1395\f
1ee5d538 1396void
971de7fb 1397syms_of_chartab (void)
1ee5d538 1398{
c805dec0
KH
1399 DEFSYM (Qchar_code_property_table, "char-code-property-table");
1400
1ee5d538
KH
1401 defsubr (&Smake_char_table);
1402 defsubr (&Schar_table_parent);
1403 defsubr (&Schar_table_subtype);
1404 defsubr (&Sset_char_table_parent);
1405 defsubr (&Schar_table_extra_slot);
1406 defsubr (&Sset_char_table_extra_slot);
1407 defsubr (&Schar_table_range);
1408 defsubr (&Sset_char_table_range);
1ee5d538
KH
1409 defsubr (&Soptimize_char_table);
1410 defsubr (&Smap_char_table);
c805dec0
KH
1411 defsubr (&Sunicode_property_table_internal);
1412 defsubr (&Sget_unicode_property_internal);
1413 defsubr (&Sput_unicode_property_internal);
1414
1415 /* Each element has the form (PROP . TABLE).
1416 PROP is a symbol representing a character property.
1417 TABLE is a char-table containing the property value for each character.
1418 TABLE may be a name of file to load to build a char-table.
1419 This variable should be modified only through
1420 `define-char-code-property'. */
1421
1422 DEFVAR_LISP ("char-code-property-alist", Vchar_code_property_alist,
1423 doc: /* Alist of character property name vs char-table containing property values.
1424Internal use only. */);
1425 Vchar_code_property_alist = Qnil;
1ee5d538 1426}