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