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