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