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