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