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