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