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