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