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