Add C interface for Unicode character property table.
[bpt/emacs.git] / src / chartab.c
CommitLineData
1ee5d538 1/* chartab.c -- char-table support
5df4f04c 2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
1ee5d538
KH
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H13PRO009
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
1ee5d538 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
1ee5d538
KH
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1ee5d538
KH
20
21#include <config.h>
d7306fe6 22#include <setjmp.h>
b4a12c67
DL
23#include "lisp.h"
24#include "character.h"
25#include "charset.h"
26#include "ccl.h"
1ee5d538
KH
27
28/* 64/16/32/128 */
29
30/* Number of elements in Nth level char-table. */
31const int chartab_size[4] =
32 { (1 << CHARTAB_SIZE_BITS_0),
33 (1 << CHARTAB_SIZE_BITS_1),
34 (1 << CHARTAB_SIZE_BITS_2),
35 (1 << CHARTAB_SIZE_BITS_3) };
36
37/* Number of characters each element of Nth level char-table
38 covers. */
38dfbee1 39static const int chartab_chars[4] =
1ee5d538
KH
40 { (1 << (CHARTAB_SIZE_BITS_1 + CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3)),
41 (1 << (CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3)),
42 (1 << CHARTAB_SIZE_BITS_3),
43 1 };
44
45/* Number of characters (in bits) each element of Nth level char-table
46 covers. */
38dfbee1 47static const int chartab_bits[4] =
1ee5d538
KH
48 { (CHARTAB_SIZE_BITS_1 + CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3),
49 (CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3),
50 CHARTAB_SIZE_BITS_3,
51 0 };
52
53#define CHARTAB_IDX(c, depth, min_char) \
54 (((c) - (min_char)) >> chartab_bits[(depth)])
55
c805dec0
KH
56\f
57/* Preamble for uniprop (Unicode character property) tables. See the
58 comment of "Unicode character property tables". */
59
60/* Purpose of uniprop tables. */
61static Lisp_Object Qchar_code_property_table;
62
63/* Types of decoder and encoder functions for uniprop values. */
64typedef Lisp_Object (*uniprop_decoder_t) (Lisp_Object, Lisp_Object);
65typedef Lisp_Object (*uniprop_encoder_t) (Lisp_Object, Lisp_Object);
66
67static Lisp_Object uniprop_table_uncompress (Lisp_Object, int);
68static uniprop_decoder_t uniprop_get_decoder (Lisp_Object);
69
70/* 1 iff TABLE is a uniprop table. */
71#define UNIPROP_TABLE_P(TABLE) \
72 (EQ (XCHAR_TABLE (TABLE)->purpose, Qchar_code_property_table) \
73 && CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (TABLE)) == 5)
74
75/* Return a decoder for values in the uniprop table TABLE. */
76#define UNIPROP_GET_DECODER(TABLE) \
77 (UNIPROP_TABLE_P (TABLE) ? uniprop_get_decoder (TABLE) : NULL)
1ee5d538 78
c805dec0
KH
79/* Nonzero iff OBJ is a string representing uniprop values of 128
80 succeeding characters (the bottom level of a char-table) by a
81 compressed format. We are sure that no property value has a string
82 starting with '\001' nor '\002'. */
83#define UNIPROP_COMPRESSED_FORM_P(OBJ) \
84 (STRINGP (OBJ) && SCHARS (OBJ) > 0 \
85 && ((SREF (OBJ, 0) == 1 || (SREF (OBJ, 0) == 2))))
86
87\f
a7ca3326 88DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0,
eaa3b0e0 89 doc: /* Return a newly created char-table, with purpose PURPOSE.
1ee5d538
KH
90Each element is initialized to INIT, which defaults to nil.
91
eaa3b0e0
KH
92PURPOSE should be a symbol. If it has a `char-table-extra-slots'
93property, the property's value should be an integer between 0 and 10
94that specifies how many extra slots the char-table has. Otherwise,
95the char-table has no extra slot. */)
5842a27b 96 (register Lisp_Object purpose, Lisp_Object init)
1ee5d538
KH
97{
98 Lisp_Object vector;
99 Lisp_Object n;
eaa3b0e0 100 int n_extras;
1ee5d538
KH
101 int size;
102
103 CHECK_SYMBOL (purpose);
eaa3b0e0
KH
104 n = Fget (purpose, Qchar_table_extra_slots);
105 if (NILP (n))
106 n_extras = 0;
107 else
1ee5d538 108 {
eaa3b0e0
KH
109 CHECK_NATNUM (n);
110 n_extras = XINT (n);
111 if (n_extras > 10)
112 args_out_of_range (n, Qnil);
1ee5d538
KH
113 }
114
115 size = VECSIZE (struct Lisp_Char_Table) - 1 + n_extras;
116 vector = Fmake_vector (make_number (size), init);
985773c9 117 XSETPVECTYPE (XVECTOR (vector), PVEC_CHAR_TABLE);
1ee5d538
KH
118 XCHAR_TABLE (vector)->parent = Qnil;
119 XCHAR_TABLE (vector)->purpose = purpose;
120 XSETCHAR_TABLE (vector, XCHAR_TABLE (vector));
121 return vector;
122}
123
124static Lisp_Object
971de7fb 125make_sub_char_table (int depth, int min_char, Lisp_Object defalt)
1ee5d538
KH
126{
127 Lisp_Object table;
128 int size = VECSIZE (struct Lisp_Sub_Char_Table) - 1 + chartab_size[depth];
1ee5d538
KH
129
130 table = Fmake_vector (make_number (size), defalt);
985773c9 131 XSETPVECTYPE (XVECTOR (table), PVEC_SUB_CHAR_TABLE);
1ee5d538
KH
132 XSUB_CHAR_TABLE (table)->depth = make_number (depth);
133 XSUB_CHAR_TABLE (table)->min_char = make_number (min_char);
1ee5d538
KH
134
135 return table;
136}
137
138static Lisp_Object
971de7fb 139char_table_ascii (Lisp_Object table)
1ee5d538 140{
c805dec0 141 Lisp_Object sub, val;
1ee5d538
KH
142
143 sub = XCHAR_TABLE (table)->contents[0];
40033db7
KH
144 if (! SUB_CHAR_TABLE_P (sub))
145 return sub;
1ee5d538 146 sub = XSUB_CHAR_TABLE (sub)->contents[0];
40033db7
KH
147 if (! SUB_CHAR_TABLE_P (sub))
148 return sub;
c805dec0
KH
149 val = XSUB_CHAR_TABLE (sub)->contents[0];
150 if (UNIPROP_TABLE_P (table) && UNIPROP_COMPRESSED_FORM_P (val))
151 val = uniprop_table_uncompress (sub, 0);
152 return val;
1ee5d538
KH
153}
154
fb93dbc2 155static Lisp_Object
971de7fb 156copy_sub_char_table (Lisp_Object table)
1ee5d538
KH
157{
158 Lisp_Object copy;
159 int depth = XINT (XSUB_CHAR_TABLE (table)->depth);
160 int min_char = XINT (XSUB_CHAR_TABLE (table)->min_char);
161 Lisp_Object val;
162 int i;
163
164 copy = make_sub_char_table (depth, min_char, Qnil);
165 /* Recursively copy any sub char-tables. */
166 for (i = 0; i < chartab_size[depth]; i++)
167 {
168 val = XSUB_CHAR_TABLE (table)->contents[i];
169 if (SUB_CHAR_TABLE_P (val))
170 XSUB_CHAR_TABLE (copy)->contents[i] = copy_sub_char_table (val);
171 else
172 XSUB_CHAR_TABLE (copy)->contents[i] = val;
173 }
174
175 return copy;
176}
177
178
179Lisp_Object
971de7fb 180copy_char_table (Lisp_Object table)
1ee5d538
KH
181{
182 Lisp_Object copy;
eab3844f 183 int size = XCHAR_TABLE (table)->header.size & PSEUDOVECTOR_SIZE_MASK;
1ee5d538
KH
184 int i;
185
186 copy = Fmake_vector (make_number (size), Qnil);
985773c9 187 XSETPVECTYPE (XVECTOR (copy), PVEC_CHAR_TABLE);
1ee5d538
KH
188 XCHAR_TABLE (copy)->defalt = XCHAR_TABLE (table)->defalt;
189 XCHAR_TABLE (copy)->parent = XCHAR_TABLE (table)->parent;
190 XCHAR_TABLE (copy)->purpose = XCHAR_TABLE (table)->purpose;
1ee5d538
KH
191 for (i = 0; i < chartab_size[0]; i++)
192 XCHAR_TABLE (copy)->contents[i]
193 = (SUB_CHAR_TABLE_P (XCHAR_TABLE (table)->contents[i])
194 ? copy_sub_char_table (XCHAR_TABLE (table)->contents[i])
195 : XCHAR_TABLE (table)->contents[i]);
d0827857 196 XCHAR_TABLE (copy)->ascii = char_table_ascii (copy);
1ee5d538
KH
197 size -= VECSIZE (struct Lisp_Char_Table) - 1;
198 for (i = 0; i < size; i++)
199 XCHAR_TABLE (copy)->extras[i] = XCHAR_TABLE (table)->extras[i];
200
201 XSETCHAR_TABLE (copy, XCHAR_TABLE (copy));
202 return copy;
203}
204
2f7c71a1 205static Lisp_Object
c805dec0 206sub_char_table_ref (Lisp_Object table, int c, int is_uniprop)
1ee5d538
KH
207{
208 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
209 int depth = XINT (tbl->depth);
210 int min_char = XINT (tbl->min_char);
211 Lisp_Object val;
c805dec0 212 int idx = CHARTAB_IDX (c, depth, min_char);
1ee5d538 213
c805dec0
KH
214 val = tbl->contents[idx];
215 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
216 val = uniprop_table_uncompress (table, idx);
1ee5d538 217 if (SUB_CHAR_TABLE_P (val))
c805dec0 218 val = sub_char_table_ref (val, c, is_uniprop);
1ee5d538
KH
219 return val;
220}
221
222Lisp_Object
971de7fb 223char_table_ref (Lisp_Object table, int c)
1ee5d538
KH
224{
225 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
226 Lisp_Object val;
227
228 if (ASCII_CHAR_P (c))
229 {
230 val = tbl->ascii;
231 if (SUB_CHAR_TABLE_P (val))
232 val = XSUB_CHAR_TABLE (val)->contents[c];
233 }
234 else
235 {
236 val = tbl->contents[CHARTAB_IDX (c, 0, 0)];
237 if (SUB_CHAR_TABLE_P (val))
c805dec0 238 val = sub_char_table_ref (val, c, UNIPROP_TABLE_P (table));
1ee5d538
KH
239 }
240 if (NILP (val))
241 {
242 val = tbl->defalt;
243 if (NILP (val) && CHAR_TABLE_P (tbl->parent))
244 val = char_table_ref (tbl->parent, c);
245 }
246 return val;
8f924df7 247}
1ee5d538
KH
248
249static Lisp_Object
c805dec0
KH
250sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to,
251 Lisp_Object defalt, int is_uniprop)
1ee5d538
KH
252{
253 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
254 int depth = XINT (tbl->depth);
255 int min_char = XINT (tbl->min_char);
5c156ace 256 int chartab_idx = CHARTAB_IDX (c, depth, min_char), idx;
1ee5d538 257 Lisp_Object val;
8f924df7 258
5c156ace 259 val = tbl->contents[chartab_idx];
c805dec0
KH
260 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
261 val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 262 if (SUB_CHAR_TABLE_P (val))
c805dec0 263 val = sub_char_table_ref_and_range (val, c, from, to, defalt, is_uniprop);
e15009d9
KH
264 else if (NILP (val))
265 val = defalt;
266
5c156ace 267 idx = chartab_idx;
7ef1f5d1 268 while (idx > 0 && *from < min_char + idx * chartab_chars[depth])
1ee5d538 269 {
e15009d9 270 Lisp_Object this_val;
e15009d9 271
7ef1f5d1
KH
272 c = min_char + idx * chartab_chars[depth] - 1;
273 idx--;
274 this_val = tbl->contents[idx];
c805dec0
KH
275 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
276 this_val = uniprop_table_uncompress (table, idx);
e15009d9 277 if (SUB_CHAR_TABLE_P (this_val))
c805dec0
KH
278 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt,
279 is_uniprop);
e15009d9
KH
280 else if (NILP (this_val))
281 this_val = defalt;
282
283 if (! EQ (this_val, val))
7ef1f5d1
KH
284 {
285 *from = c + 1;
286 break;
287 }
1ee5d538 288 }
fe75f926
PE
289 while (((c = (chartab_idx + 1) * chartab_chars[depth])
290 < chartab_chars[depth - 1])
291 && (c += min_char) <= *to)
1ee5d538 292 {
e15009d9 293 Lisp_Object this_val;
e15009d9 294
5c156ace
PE
295 chartab_idx++;
296 this_val = tbl->contents[chartab_idx];
c805dec0
KH
297 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
298 this_val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 299 if (SUB_CHAR_TABLE_P (this_val))
c805dec0
KH
300 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt,
301 is_uniprop);
e15009d9
KH
302 else if (NILP (this_val))
303 this_val = defalt;
304 if (! EQ (this_val, val))
7ef1f5d1
KH
305 {
306 *to = c - 1;
307 break;
308 }
1ee5d538 309 }
e15009d9 310
1ee5d538
KH
311 return val;
312}
313
314
7ef1f5d1
KH
315/* Return the value for C in char-table TABLE. Shrink the range *FROM
316 and *TO to cover characters (containing C) that have the same value
317 as C. It is not assured that the values of (*FROM - 1) and (*TO +
318 1) are different from that of C. */
e15009d9 319
1ee5d538 320Lisp_Object
971de7fb 321char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
1ee5d538
KH
322{
323 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
5c156ace 324 int chartab_idx = CHARTAB_IDX (c, 0, 0), idx;
1ee5d538 325 Lisp_Object val;
c805dec0 326 int is_uniprop = UNIPROP_TABLE_P (table);
1ee5d538 327
5c156ace 328 val = tbl->contents[chartab_idx];
7ef1f5d1
KH
329 if (*from < 0)
330 *from = 0;
331 if (*to < 0)
332 *to = MAX_CHAR;
c805dec0
KH
333 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
334 val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 335 if (SUB_CHAR_TABLE_P (val))
c805dec0
KH
336 val = sub_char_table_ref_and_range (val, c, from, to, tbl->defalt,
337 is_uniprop);
e15009d9
KH
338 else if (NILP (val))
339 val = tbl->defalt;
5c156ace 340 idx = chartab_idx;
7ef1f5d1 341 while (*from < idx * chartab_chars[0])
1ee5d538 342 {
e15009d9 343 Lisp_Object this_val;
e15009d9 344
7ef1f5d1
KH
345 c = idx * chartab_chars[0] - 1;
346 idx--;
347 this_val = tbl->contents[idx];
c805dec0
KH
348 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
349 this_val = uniprop_table_uncompress (table, idx);
e15009d9 350 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 351 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
c805dec0 352 tbl->defalt, is_uniprop);
e15009d9
KH
353 else if (NILP (this_val))
354 this_val = tbl->defalt;
355
356 if (! EQ (this_val, val))
7ef1f5d1
KH
357 {
358 *from = c + 1;
359 break;
360 }
1ee5d538 361 }
5c156ace 362 while (*to >= (chartab_idx + 1) * chartab_chars[0])
1ee5d538 363 {
e15009d9 364 Lisp_Object this_val;
e15009d9 365
5c156ace
PE
366 chartab_idx++;
367 c = chartab_idx * chartab_chars[0];
368 this_val = tbl->contents[chartab_idx];
c805dec0
KH
369 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
370 this_val = uniprop_table_uncompress (table, chartab_idx);
e15009d9 371 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 372 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
c805dec0 373 tbl->defalt, is_uniprop);
e15009d9
KH
374 else if (NILP (this_val))
375 this_val = tbl->defalt;
376 if (! EQ (this_val, val))
7ef1f5d1
KH
377 {
378 *to = c - 1;
379 break;
380 }
1ee5d538
KH
381 }
382
1ee5d538 383 return val;
e15009d9 384}
1ee5d538
KH
385
386
1ee5d538 387static void
c805dec0 388sub_char_table_set (Lisp_Object table, int c, Lisp_Object val, int is_uniprop)
1ee5d538
KH
389{
390 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
391 int depth = XINT ((tbl)->depth);
392 int min_char = XINT ((tbl)->min_char);
393 int i = CHARTAB_IDX (c, depth, min_char);
394 Lisp_Object sub;
8f924df7 395
1ee5d538
KH
396 if (depth == 3)
397 tbl->contents[i] = val;
398 else
399 {
400 sub = tbl->contents[i];
401 if (! SUB_CHAR_TABLE_P (sub))
402 {
c805dec0
KH
403 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (sub))
404 sub = uniprop_table_uncompress (table, i);
405 else
406 {
407 sub = make_sub_char_table (depth + 1,
408 min_char + i * chartab_chars[depth],
409 sub);
410 tbl->contents[i] = sub;
411 }
1ee5d538 412 }
c805dec0 413 sub_char_table_set (sub, c, val, is_uniprop);
1ee5d538
KH
414 }
415}
416
417Lisp_Object
971de7fb 418char_table_set (Lisp_Object table, int c, Lisp_Object val)
1ee5d538
KH
419{
420 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
421
422 if (ASCII_CHAR_P (c)
423 && SUB_CHAR_TABLE_P (tbl->ascii))
424 {
425 XSUB_CHAR_TABLE (tbl->ascii)->contents[c] = val;
426 }
427 else
428 {
429 int i = CHARTAB_IDX (c, 0, 0);
430 Lisp_Object sub;
431
432 sub = tbl->contents[i];
433 if (! SUB_CHAR_TABLE_P (sub))
434 {
435 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
436 tbl->contents[i] = sub;
437 }
c805dec0 438 sub_char_table_set (sub, c, val, UNIPROP_TABLE_P (table));
1ee5d538 439 if (ASCII_CHAR_P (c))
40033db7 440 tbl->ascii = char_table_ascii (table);
1ee5d538
KH
441 }
442 return val;
443}
444
445static void
c805dec0
KH
446sub_char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val,
447 int is_uniprop)
1ee5d538 448{
c805dec0
KH
449 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
450 int depth = XINT ((tbl)->depth);
451 int min_char = XINT ((tbl)->min_char);
452 int chars_in_block = chartab_chars[depth];
453 int i, c, lim = chartab_size[depth];
454
455 if (from < min_char)
456 from = min_char;
457 i = CHARTAB_IDX (from, depth, min_char);
458 c = min_char + chars_in_block * i;
459 for (; i <= lim; i++, c += chars_in_block)
1ee5d538 460 {
c805dec0
KH
461 if (c > to)
462 break;
463 if (from <= c && c + chars_in_block - 1 <= to)
464 tbl->contents[i] = val;
465 else
466 {
467 Lisp_Object sub = tbl->contents[i];
468 if (! SUB_CHAR_TABLE_P (sub))
469 {
470 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (sub))
471 sub = uniprop_table_uncompress (table, i);
472 else
473 {
474 sub = make_sub_char_table (depth + 1, c, sub);
475 tbl->contents[i] = sub;
476 }
477 }
478 sub_char_table_set_range (sub, from, to, val, is_uniprop);
479 }
1ee5d538
KH
480 }
481}
482
483
484Lisp_Object
971de7fb 485char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val)
1ee5d538
KH
486{
487 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
488 Lisp_Object *contents = tbl->contents;
1ee5d538
KH
489
490 if (from == to)
491 char_table_set (table, from, val);
492 else
493 {
c805dec0
KH
494 int is_uniprop = UNIPROP_TABLE_P (table);
495 int lim = CHARTAB_IDX (to, 0, 0);
496 int i, c;
497
498 for (i = CHARTAB_IDX (from, 0, 0), c = 0; i <= lim;
499 i++, c += chartab_chars[0])
500 {
501 if (c > to)
502 break;
503 if (from <= c && c + chartab_chars[0] - 1 <= to)
504 tbl->contents[i] = val;
505 else
506 {
507 Lisp_Object sub = tbl->contents[i];
508 if (! SUB_CHAR_TABLE_P (sub))
509 {
510 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
511 tbl->contents[i] = sub;
512 }
513 sub_char_table_set_range (sub, from, to, val, is_uniprop);
514 }
515 }
1ee5d538 516 if (ASCII_CHAR_P (from))
40033db7 517 tbl->ascii = char_table_ascii (table);
1ee5d538
KH
518 }
519 return val;
520}
521
522\f
523DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
524 1, 1, 0,
525 doc: /*
526Return the subtype of char-table CHAR-TABLE. The value is a symbol. */)
5842a27b 527 (Lisp_Object char_table)
1ee5d538
KH
528{
529 CHECK_CHAR_TABLE (char_table);
530
531 return XCHAR_TABLE (char_table)->purpose;
532}
533
534DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
535 1, 1, 0,
536 doc: /* Return the parent char-table of CHAR-TABLE.
537The value is either nil or another char-table.
538If CHAR-TABLE holds nil for a given character,
539then the actual applicable value is inherited from the parent char-table
540\(or from its parents, if necessary). */)
5842a27b 541 (Lisp_Object char_table)
1ee5d538
KH
542{
543 CHECK_CHAR_TABLE (char_table);
544
545 return XCHAR_TABLE (char_table)->parent;
546}
547
a7ca3326 548DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
1ee5d538
KH
549 2, 2, 0,
550 doc: /* Set the parent char-table of CHAR-TABLE to PARENT.
6b61353c 551Return PARENT. PARENT must be either nil or another char-table. */)
5842a27b 552 (Lisp_Object char_table, Lisp_Object parent)
1ee5d538
KH
553{
554 Lisp_Object temp;
555
556 CHECK_CHAR_TABLE (char_table);
557
558 if (!NILP (parent))
559 {
560 CHECK_CHAR_TABLE (parent);
561
562 for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
563 if (EQ (temp, char_table))
564 error ("Attempt to make a chartable be its own parent");
565 }
566
567 XCHAR_TABLE (char_table)->parent = parent;
568
569 return parent;
570}
571
a7ca3326 572DEFUN ("char-table-extra-slot", Fchar_table_extra_slot, Schar_table_extra_slot,
1ee5d538
KH
573 2, 2, 0,
574 doc: /* Return the value of CHAR-TABLE's extra-slot number N. */)
5842a27b 575 (Lisp_Object char_table, Lisp_Object n)
1ee5d538
KH
576{
577 CHECK_CHAR_TABLE (char_table);
578 CHECK_NUMBER (n);
579 if (XINT (n) < 0
580 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
581 args_out_of_range (char_table, n);
582
583 return XCHAR_TABLE (char_table)->extras[XINT (n)];
584}
585
a7ca3326 586DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
1ee5d538
KH
587 Sset_char_table_extra_slot,
588 3, 3, 0,
589 doc: /* Set CHAR-TABLE's extra-slot number N to VALUE. */)
5842a27b 590 (Lisp_Object char_table, Lisp_Object n, Lisp_Object value)
1ee5d538
KH
591{
592 CHECK_CHAR_TABLE (char_table);
c805dec0
KH
593 if (EQ (XCHAR_TABLE (char_table)->purpose, Qchar_code_property_table))
594 error ("Can't change extra-slot of char-code-property-table");
1ee5d538
KH
595 CHECK_NUMBER (n);
596 if (XINT (n) < 0
597 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
598 args_out_of_range (char_table, n);
599
600 return XCHAR_TABLE (char_table)->extras[XINT (n)] = value;
601}
602\f
603DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
604 2, 2, 0,
605 doc: /* Return the value in CHAR-TABLE for a range of characters RANGE.
606RANGE should be nil (for the default value),
607a cons of character codes (for characters in the range), or a character code. */)
5842a27b 608 (Lisp_Object char_table, Lisp_Object range)
1ee5d538
KH
609{
610 Lisp_Object val;
611 CHECK_CHAR_TABLE (char_table);
612
613 if (EQ (range, Qnil))
614 val = XCHAR_TABLE (char_table)->defalt;
8fd02eb7
PE
615 else if (CHARACTERP (range))
616 val = CHAR_TABLE_REF (char_table, XFASTINT (range));
1ee5d538
KH
617 else if (CONSP (range))
618 {
619 int from, to;
620
8f924df7
KH
621 CHECK_CHARACTER_CAR (range);
622 CHECK_CHARACTER_CDR (range);
c805dec0
KH
623 from = XFASTINT (XCAR (range));
624 to = XFASTINT (XCDR (range));
625 val = char_table_ref_and_range (char_table, from, &from, &to);
1ee5d538
KH
626 /* Not yet implemented. */
627 }
628 else
629 error ("Invalid RANGE argument to `char-table-range'");
630 return val;
631}
632
a7ca3326 633DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
1ee5d538 634 3, 3, 0,
6b61353c 635 doc: /* Set the value in CHAR-TABLE for a range of characters RANGE to VALUE.
1ee5d538 636RANGE should be t (for all characters), nil (for the default value),
6b61353c
KH
637a cons of character codes (for characters in the range),
638or a character code. Return VALUE. */)
5842a27b 639 (Lisp_Object char_table, Lisp_Object range, Lisp_Object value)
1ee5d538
KH
640{
641 CHECK_CHAR_TABLE (char_table);
642 if (EQ (range, Qt))
643 {
644 int i;
645
c6bff69e 646 XCHAR_TABLE (char_table)->ascii = value;
1ee5d538 647 for (i = 0; i < chartab_size[0]; i++)
c6bff69e 648 XCHAR_TABLE (char_table)->contents[i] = value;
1ee5d538
KH
649 }
650 else if (EQ (range, Qnil))
651 XCHAR_TABLE (char_table)->defalt = value;
652 else if (INTEGERP (range))
653 char_table_set (char_table, XINT (range), value);
654 else if (CONSP (range))
655 {
8f924df7
KH
656 CHECK_CHARACTER_CAR (range);
657 CHECK_CHARACTER_CDR (range);
1ee5d538
KH
658 char_table_set_range (char_table,
659 XINT (XCAR (range)), XINT (XCDR (range)), value);
660 }
661 else
662 error ("Invalid RANGE argument to `set-char-table-range'");
663
664 return value;
665}
666
667DEFUN ("set-char-table-default", Fset_char_table_default,
668 Sset_char_table_default, 3, 3, 0,
669 doc: /*
f6e5cae0 670This function is obsolete and has no effect. */)
5842a27b 671 (Lisp_Object char_table, Lisp_Object ch, Lisp_Object value)
1ee5d538
KH
672{
673 return Qnil;
674}
675
676/* Look up the element in TABLE at index CH, and return it as an
05d6275c 677 integer. If the element is not a character, return CH itself. */
1ee5d538
KH
678
679int
971de7fb 680char_table_translate (Lisp_Object table, int ch)
1ee5d538
KH
681{
682 Lisp_Object value;
683 value = Faref (table, make_number (ch));
05d6275c 684 if (! CHARACTERP (value))
1ee5d538
KH
685 return ch;
686 return XINT (value);
687}
688
689static Lisp_Object
971de7fb 690optimize_sub_char_table (Lisp_Object table, Lisp_Object test)
1ee5d538
KH
691{
692 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
693 int depth = XINT (tbl->depth);
694 Lisp_Object elt, this;
c3b57f23 695 int i, optimizable;
1ee5d538
KH
696
697 elt = XSUB_CHAR_TABLE (table)->contents[0];
698 if (SUB_CHAR_TABLE_P (elt))
d0827857
SM
699 elt = XSUB_CHAR_TABLE (table)->contents[0]
700 = optimize_sub_char_table (elt, test);
c3b57f23 701 optimizable = SUB_CHAR_TABLE_P (elt) ? 0 : 1;
1ee5d538
KH
702 for (i = 1; i < chartab_size[depth]; i++)
703 {
704 this = XSUB_CHAR_TABLE (table)->contents[i];
705 if (SUB_CHAR_TABLE_P (this))
706 this = XSUB_CHAR_TABLE (table)->contents[i]
d0827857 707 = optimize_sub_char_table (this, test);
c3b57f23
KH
708 if (optimizable
709 && (NILP (test) ? NILP (Fequal (this, elt)) /* defaults to `equal'. */
d0827857
SM
710 : EQ (test, Qeq) ? !EQ (this, elt) /* Optimize `eq' case. */
711 : NILP (call2 (test, this, elt))))
c3b57f23 712 optimizable = 0;
1ee5d538
KH
713 }
714
c3b57f23 715 return (optimizable ? elt : table);
1ee5d538
KH
716}
717
a7ca3326 718DEFUN ("optimize-char-table", Foptimize_char_table, Soptimize_char_table,
d0827857
SM
719 1, 2, 0,
720 doc: /* Optimize CHAR-TABLE.
721TEST is the comparison function used to decide whether two entries are
722equivalent and can be merged. It defaults to `equal'. */)
5842a27b 723 (Lisp_Object char_table, Lisp_Object test)
1ee5d538
KH
724{
725 Lisp_Object elt;
726 int i;
727
728 CHECK_CHAR_TABLE (char_table);
729
730 for (i = 0; i < chartab_size[0]; i++)
731 {
732 elt = XCHAR_TABLE (char_table)->contents[i];
733 if (SUB_CHAR_TABLE_P (elt))
d0827857
SM
734 XCHAR_TABLE (char_table)->contents[i]
735 = optimize_sub_char_table (elt, test);
1ee5d538 736 }
4d632321
SM
737 /* Reset the `ascii' cache, in case it got optimized away. */
738 XCHAR_TABLE (char_table)->ascii = char_table_ascii (char_table);
739
1ee5d538
KH
740 return Qnil;
741}
742
743\f
57d53d1b
KH
744/* Map C_FUNCTION or FUNCTION over TABLE (top or sub char-table),
745 calling it for each character or group of characters that share a
746 value. RANGE is a cons (FROM . TO) specifying the range of target
c805dec0 747 characters, VAL is a value of FROM in TABLE, TOP is the top
57d53d1b
KH
748 char-table.
749
750 ARG is passed to C_FUNCTION when that is called.
751
752 It returns the value of last character covered by TABLE (not the
753 value inheritted from the parent), and by side-effect, the car part
754 of RANGE is updated to the minimum character C where C and all the
755 following characters in TABLE have the same value. */
756
1ee5d538 757static Lisp_Object
dd4c5104
DN
758map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
759 Lisp_Object function, Lisp_Object table, Lisp_Object arg, Lisp_Object val,
c805dec0 760 Lisp_Object range, Lisp_Object top)
1ee5d538 761{
57d53d1b
KH
762 /* Pointer to the elements of TABLE. */
763 Lisp_Object *contents;
764 /* Depth of TABLE. */
765 int depth;
766 /* Minimum and maxinum characters covered by TABLE. */
767 int min_char, max_char;
768 /* Number of characters covered by one element of TABLE. */
769 int chars_in_block;
770 int from = XINT (XCAR (range)), to = XINT (XCDR (range));
1ee5d538 771 int i, c;
c805dec0
KH
772 int is_uniprop = UNIPROP_TABLE_P (top);
773 uniprop_decoder_t decoder = UNIPROP_GET_DECODER (top);
1ee5d538 774
57d53d1b
KH
775 if (SUB_CHAR_TABLE_P (table))
776 {
777 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
778
779 depth = XINT (tbl->depth);
780 contents = tbl->contents;
781 min_char = XINT (tbl->min_char);
782 max_char = min_char + chartab_chars[depth - 1] - 1;
783 }
784 else
785 {
786 depth = 0;
787 contents = XCHAR_TABLE (table)->contents;
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 {
57d53d1b
KH
823 int different_value = 1;
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. */
834 XCHAR_TABLE (parent)->parent = Qnil;
835 val = CHAR_TABLE_REF (parent, from);
836 XCHAR_TABLE (parent)->parent = temp;
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. */
916 XCHAR_TABLE (parent)->parent = Qnil;
917 val = CHAR_TABLE_REF (parent, from);
918 XCHAR_TABLE (parent)->parent = temp;
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,
955 doc: /*
ed7219f8 956Call FUNCTION for each character in CHAR-TABLE that has non-nil value.
1ee5d538 957FUNCTION is called with two arguments--a key and a value.
2f76e15e
KH
958The key is a character code or a cons of character codes specifying a
959range of characters that have the same value. */)
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
1103 This section provides a convenient and efficient way to get a
1104 Unicode character property from C code (from Lisp, you must use
1105 get-char-code-property).
1106
1107 The typical usage is to get a char-table for a specific property at
1108 a proper initialization time as this:
1109
1110 Lisp_Object bidi_class_table = uniprop_table (intern ("bidi-class"));
1111
1112 and get a property value for character CH as this:
1113
1114 Lisp_Object bidi_class = CHAR_TABLE_REF (CH, bidi_class_table);
1115
1116 In this case, what you actually get is an index number to the
1117 vector of property values (symbols nil, L, R, etc).
1118
1119 A table for Unicode character property has these characteristics:
1120
1121 o The purpose is `char-code-property-table', which implies that the
1122 table has 5 extra slots.
1123
1124 o The second extra slot is a Lisp function, an index (integer) to
1125 the array uniprop_decoder[], or nil. If it is a Lisp function, we
1126 can't use such a table from C (at the moment). If it is nil, it
1127 means that we don't have to decode values.
1128
1129 o The third extra slot is a Lisp function, an index (integer) to
1130 the array uniprop_enncoder[], or nil. If it is a Lisp function, we
1131 can't use such a table from C (at the moment). If it is nil, it
1132 means that we don't have to encode values. */
1133
1134
1135/* Uncompress the IDXth element of sub-char-table TABLE. */
1136
1137static Lisp_Object
1138uniprop_table_uncompress (Lisp_Object table, int idx)
1139{
1140 Lisp_Object val = XSUB_CHAR_TABLE (table)->contents[idx];
1141 int min_char = (XINT (XSUB_CHAR_TABLE (table)->min_char)
1142 + chartab_chars[2] * idx);
1143 Lisp_Object sub = make_sub_char_table (3, min_char, Qnil);
1144 struct Lisp_Sub_Char_Table *subtbl = XSUB_CHAR_TABLE (sub);
1145 const unsigned char *p, *pend;
1146 int i;
1147
1148 XSUB_CHAR_TABLE (table)->contents[idx] = sub;
1149 p = SDATA (val), pend = p + SBYTES (val);
1150 if (*p == 1)
1151 {
1152 /* SIMPLE TABLE */
1153 p++;
1154 idx = STRING_CHAR_ADVANCE (p);
1155 while (p < pend && idx < chartab_chars[2])
1156 {
1157 int v = STRING_CHAR_ADVANCE (p);
1158 subtbl->contents[idx++] = v > 0 ? make_number (v) : Qnil;
1159 }
1160 }
1161 else if (*p == 2)
1162 {
1163 /* RUN-LENGTH TABLE */
1164 p++;
1165 for (idx = 0; p < pend; )
1166 {
1167 int v = STRING_CHAR_ADVANCE (p);
1168 int count = 1;
1169 int len;
1170
1171 if (p < pend)
1172 {
1173 count = STRING_CHAR_AND_LENGTH (p, len);
1174 if (count < 128)
1175 count = 1;
1176 else
1177 {
1178 count -= 128;
1179 p += len;
1180 }
1181 }
1182 while (count-- > 0)
1183 subtbl->contents[idx++] = make_number (v);
1184 }
1185 }
1186/* It seems that we don't need this function because C code won't need
1187 to get a property that is compressed in this form. */
1188#if 0
1189 else if (*p == 0)
1190 {
1191 /* WORD-LIST TABLE */
1192 }
1193#endif
1194 return sub;
1195}
1196
1197
1198/* Decode VALUE as an elemnet of char-table TABLE. */
1199
1200static Lisp_Object
1201uniprop_decode_value_run_length (Lisp_Object table, Lisp_Object value)
1202{
1203 if (VECTORP (XCHAR_TABLE (table)->extras[4]))
1204 {
1205 Lisp_Object valvec = XCHAR_TABLE (table)->extras[4];
1206
1207 if (XINT (value) >= 0 && XINT (value) < ASIZE (valvec))
1208 value = AREF (valvec, XINT (value));
1209 }
1210 return value;
1211}
1212
1213static uniprop_decoder_t uniprop_decoder [] =
1214 { uniprop_decode_value_run_length };
1215
1216static int uniprop_decoder_count
1217 = (sizeof uniprop_decoder) / sizeof (uniprop_decoder[0]);
1218
1219
1220/* Return the decoder of char-table TABLE or nil if none. */
1221
1222static uniprop_decoder_t
1223uniprop_get_decoder (Lisp_Object table)
1224{
1225 int i;
1226
1227 if (! INTEGERP (XCHAR_TABLE (table)->extras[1]))
1228 return NULL;
1229 i = XINT (XCHAR_TABLE (table)->extras[1]);
1230 if (i < 0 || i >= uniprop_decoder_count)
1231 return NULL;
1232 return uniprop_decoder[i];
1233}
1234
1235
1236/* Encode VALUE as an element of char-table TABLE which contains
1237 characters as elements. */
1238
1239static Lisp_Object
1240uniprop_encode_value_character (Lisp_Object table, Lisp_Object value)
1241{
1242 if (! NILP (value) && ! CHARACTERP (value))
1243 wrong_type_argument (Qintegerp, value);
1244 return value;
1245}
1246
1247
1248/* Encode VALUE as an element of char-table TABLE which adopts RUN-LENGTH
1249 compression. */
1250
1251static Lisp_Object
1252uniprop_encode_value_run_length (Lisp_Object table, Lisp_Object value)
1253{
1254 Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
1255 int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
1256
1257 for (i = 0; i < size; i++)
1258 if (EQ (value, value_table[i]))
1259 break;
1260 if (i == size)
1261 wrong_type_argument (build_string ("Unicode property value"), value);
1262 return make_number (i);
1263}
1264
1265
1266/* Encode VALUE as an element of char-table TABLE which adopts RUN-LENGTH
1267 compression and contains numbers as elements . */
1268
1269static Lisp_Object
1270uniprop_encode_value_numeric (Lisp_Object table, Lisp_Object value)
1271{
1272 Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
1273 int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
1274
1275 CHECK_NUMBER (value);
1276 for (i = 0; i < size; i++)
1277 if (EQ (value, value_table[i]))
1278 break;
1279 value = make_number (i);
1280 if (i == size)
1281 {
1282 Lisp_Object args[2];
1283
1284 args[0] = XCHAR_TABLE (table)->extras[4];
1285 args[1] = Fmake_vector (make_number (1), value);
1286 XCHAR_TABLE (table)->extras[4] = Fvconcat (2, args);
1287 }
1288 return make_number (i);
1289}
1290
1291static uniprop_encoder_t uniprop_encoder[] =
1292 { uniprop_encode_value_character,
1293 uniprop_encode_value_run_length,
1294 uniprop_encode_value_numeric };
1295
1296static int uniprop_encoder_count
1297 = (sizeof uniprop_encoder) / sizeof (uniprop_encoder[0]);
1298
1299
1300/* Return the encoder of char-table TABLE or nil if none. */
1301
1302static uniprop_decoder_t
1303uniprop_get_encoder (Lisp_Object table)
1304{
1305 int i;
1306
1307 if (! INTEGERP (XCHAR_TABLE (table)->extras[2]))
1308 return NULL;
1309 i = XINT (XCHAR_TABLE (table)->extras[2]);
1310 if (i < 0 || i >= uniprop_encoder_count)
1311 return NULL;
1312 return uniprop_encoder[i];
1313}
1314
1315/* Return a char-table for Unicode character property PROP. This
1316 function may load a Lisp file and thus may cause
1317 garbage-collection. */
1318
1319Lisp_Object
1320uniprop_table (Lisp_Object prop)
1321{
1322 Lisp_Object val, table, result;
1323
1324 val = Fassq (prop, Vchar_code_property_alist);
1325 if (! CONSP (val))
1326 return Qnil;
1327 table = XCDR (val);
1328 if (STRINGP (table))
1329 {
1330 struct gcpro gcpro1;
1331 GCPRO1 (val);
1332 result = Fload (concat2 (build_string ("international/"), table),
1333 Qt, Qt, Qt, Qt);
1334 UNGCPRO;
1335 if (NILP (result))
1336 return Qnil;
1337 table = XCDR (val);
1338 }
1339 if (! CHAR_TABLE_P (table)
1340 || ! UNIPROP_TABLE_P (table))
1341 return Qnil;
1342 val = XCHAR_TABLE (table)->extras[1];
1343 if (INTEGERP (val)
1344 ? (XINT (val) < 0 || XINT (val) >= uniprop_decoder_count)
1345 : ! NILP (val))
1346 return Qnil;
1347 /* Prepare ASCII values in advance for CHAR_TABLE_REF. */
1348 XCHAR_TABLE (table)->ascii = char_table_ascii (table);
1349 return table;
1350}
1351
1352DEFUN ("unicode-property-table-internal", Funicode_property_table_internal,
1353 Sunicode_property_table_internal, 1, 1, 0,
1354 doc: /* Return a char-table for Unicode character property PROP.
1355Use `get-unicode-property-internal' and
1356`put-unicode-property-internal' instead of `aref' and `aset' to get
1357and put an element value. */)
1358 (Lisp_Object prop)
1359{
1360 Lisp_Object table = uniprop_table (prop);
1361
1362 if (CHAR_TABLE_P (table))
1363 return table;
1364 return Fcdr (Fassq (prop, Vchar_code_property_alist));
1365}
1366
1367DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal,
1368 Sget_unicode_property_internal, 2, 2, 0,
1369 doc: /* Return an element of CHAR-TABLE for character CH.
1370CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1371 (Lisp_Object char_table, Lisp_Object ch)
1372{
1373 Lisp_Object val;
1374 uniprop_decoder_t decoder;
1375
1376 CHECK_CHAR_TABLE (char_table);
1377 CHECK_CHARACTER (ch);
1378 if (! UNIPROP_TABLE_P (char_table))
1379 error ("Invalid Unicode property table");
1380 val = CHAR_TABLE_REF (char_table, XINT (ch));
1381 decoder = uniprop_get_decoder (char_table);
1382 return (decoder ? decoder (char_table, val) : val);
1383}
1384
1385DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal,
1386 Sput_unicode_property_internal, 3, 3, 0,
1387 doc: /* Set an element of CHAR-TABLE for character CH to VALUE.
1388CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1389 (Lisp_Object char_table, Lisp_Object ch, Lisp_Object value)
1390{
1391 uniprop_encoder_t encoder;
1392
1393 CHECK_CHAR_TABLE (char_table);
1394 CHECK_CHARACTER (ch);
1395 if (! UNIPROP_TABLE_P (char_table))
1396 error ("Invalid Unicode property table");
1397 encoder = uniprop_get_encoder (char_table);
1398 if (encoder)
1399 value = encoder (char_table, value);
1400 CHAR_TABLE_SET (char_table, XINT (ch), value);
1401 return Qnil;
1402}
1403
1404\f
1ee5d538 1405void
971de7fb 1406syms_of_chartab (void)
1ee5d538 1407{
c805dec0
KH
1408 DEFSYM (Qchar_code_property_table, "char-code-property-table");
1409
1ee5d538
KH
1410 defsubr (&Smake_char_table);
1411 defsubr (&Schar_table_parent);
1412 defsubr (&Schar_table_subtype);
1413 defsubr (&Sset_char_table_parent);
1414 defsubr (&Schar_table_extra_slot);
1415 defsubr (&Sset_char_table_extra_slot);
1416 defsubr (&Schar_table_range);
1417 defsubr (&Sset_char_table_range);
1418 defsubr (&Sset_char_table_default);
1419 defsubr (&Soptimize_char_table);
1420 defsubr (&Smap_char_table);
c805dec0
KH
1421 defsubr (&Sunicode_property_table_internal);
1422 defsubr (&Sget_unicode_property_internal);
1423 defsubr (&Sput_unicode_property_internal);
1424
1425 /* Each element has the form (PROP . TABLE).
1426 PROP is a symbol representing a character property.
1427 TABLE is a char-table containing the property value for each character.
1428 TABLE may be a name of file to load to build a char-table.
1429 This variable should be modified only through
1430 `define-char-code-property'. */
1431
1432 DEFVAR_LISP ("char-code-property-alist", Vchar_code_property_alist,
1433 doc: /* Alist of character property name vs char-table containing property values.
1434Internal use only. */);
1435 Vchar_code_property_alist = Qnil;
1ee5d538 1436}