MAINTAINERS: Update Eli Zaretskii's responsibilities.
[bpt/emacs.git] / src / chartab.c
CommitLineData
1ee5d538 1/* chartab.c -- char-table support
114f9c96 2 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
1ee5d538
KH
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H13PRO009
5
6This file is part of GNU Emacs.
7
9ec0b715 8GNU Emacs is free software: you can redistribute it and/or modify
1ee5d538 9it under the terms of the GNU General Public License as published by
9ec0b715
GM
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
1ee5d538
KH
12
13GNU Emacs is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
9ec0b715 19along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
1ee5d538
KH
20
21#include <config.h>
d7306fe6 22#include <setjmp.h>
b4a12c67
DL
23#include "lisp.h"
24#include "character.h"
25#include "charset.h"
26#include "ccl.h"
1ee5d538
KH
27
28/* 64/16/32/128 */
29
30/* Number of elements in Nth level char-table. */
31const 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. */
39const 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. */
47const 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
57DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0,
eaa3b0e0 58 doc: /* Return a newly created char-table, with purpose PURPOSE.
1ee5d538
KH
59Each element is initialized to INIT, which defaults to nil.
60
eaa3b0e0
KH
61PURPOSE should be a symbol. If it has a `char-table-extra-slots'
62property, the property's value should be an integer between 0 and 10
63that specifies how many extra slots the char-table has. Otherwise,
64the char-table has no extra slot. */)
1ee5d538
KH
65 (purpose, init)
66 register Lisp_Object purpose, init;
67{
68 Lisp_Object vector;
69 Lisp_Object n;
eaa3b0e0 70 int n_extras;
1ee5d538
KH
71 int size;
72
73 CHECK_SYMBOL (purpose);
eaa3b0e0
KH
74 n = Fget (purpose, Qchar_table_extra_slots);
75 if (NILP (n))
76 n_extras = 0;
77 else
1ee5d538 78 {
eaa3b0e0
KH
79 CHECK_NATNUM (n);
80 n_extras = XINT (n);
81 if (n_extras > 10)
82 args_out_of_range (n, Qnil);
1ee5d538
KH
83 }
84
85 size = VECSIZE (struct Lisp_Char_Table) - 1 + n_extras;
86 vector = Fmake_vector (make_number (size), init);
985773c9 87 XSETPVECTYPE (XVECTOR (vector), PVEC_CHAR_TABLE);
1ee5d538
KH
88 XCHAR_TABLE (vector)->parent = Qnil;
89 XCHAR_TABLE (vector)->purpose = purpose;
90 XSETCHAR_TABLE (vector, XCHAR_TABLE (vector));
91 return vector;
92}
93
94static Lisp_Object
971de7fb 95make_sub_char_table (int depth, int min_char, Lisp_Object defalt)
1ee5d538
KH
96{
97 Lisp_Object table;
98 int size = VECSIZE (struct Lisp_Sub_Char_Table) - 1 + chartab_size[depth];
1ee5d538
KH
99
100 table = Fmake_vector (make_number (size), defalt);
985773c9 101 XSETPVECTYPE (XVECTOR (table), PVEC_SUB_CHAR_TABLE);
1ee5d538
KH
102 XSUB_CHAR_TABLE (table)->depth = make_number (depth);
103 XSUB_CHAR_TABLE (table)->min_char = make_number (min_char);
1ee5d538
KH
104
105 return table;
106}
107
108static Lisp_Object
971de7fb 109char_table_ascii (Lisp_Object table)
1ee5d538
KH
110{
111 Lisp_Object sub;
112
113 sub = XCHAR_TABLE (table)->contents[0];
40033db7
KH
114 if (! SUB_CHAR_TABLE_P (sub))
115 return sub;
1ee5d538 116 sub = XSUB_CHAR_TABLE (sub)->contents[0];
40033db7
KH
117 if (! SUB_CHAR_TABLE_P (sub))
118 return sub;
1ee5d538
KH
119 return XSUB_CHAR_TABLE (sub)->contents[0];
120}
121
122Lisp_Object
971de7fb 123copy_sub_char_table (Lisp_Object table)
1ee5d538
KH
124{
125 Lisp_Object copy;
126 int depth = XINT (XSUB_CHAR_TABLE (table)->depth);
127 int min_char = XINT (XSUB_CHAR_TABLE (table)->min_char);
128 Lisp_Object val;
129 int i;
130
131 copy = make_sub_char_table (depth, min_char, Qnil);
132 /* Recursively copy any sub char-tables. */
133 for (i = 0; i < chartab_size[depth]; i++)
134 {
135 val = XSUB_CHAR_TABLE (table)->contents[i];
136 if (SUB_CHAR_TABLE_P (val))
137 XSUB_CHAR_TABLE (copy)->contents[i] = copy_sub_char_table (val);
138 else
139 XSUB_CHAR_TABLE (copy)->contents[i] = val;
140 }
141
142 return copy;
143}
144
145
146Lisp_Object
971de7fb 147copy_char_table (Lisp_Object table)
1ee5d538
KH
148{
149 Lisp_Object copy;
150 int size = XCHAR_TABLE (table)->size & PSEUDOVECTOR_SIZE_MASK;
151 int i;
152
153 copy = Fmake_vector (make_number (size), Qnil);
985773c9 154 XSETPVECTYPE (XVECTOR (copy), PVEC_CHAR_TABLE);
1ee5d538
KH
155 XCHAR_TABLE (copy)->defalt = XCHAR_TABLE (table)->defalt;
156 XCHAR_TABLE (copy)->parent = XCHAR_TABLE (table)->parent;
157 XCHAR_TABLE (copy)->purpose = XCHAR_TABLE (table)->purpose;
1ee5d538
KH
158 for (i = 0; i < chartab_size[0]; i++)
159 XCHAR_TABLE (copy)->contents[i]
160 = (SUB_CHAR_TABLE_P (XCHAR_TABLE (table)->contents[i])
161 ? copy_sub_char_table (XCHAR_TABLE (table)->contents[i])
162 : XCHAR_TABLE (table)->contents[i]);
d0827857 163 XCHAR_TABLE (copy)->ascii = char_table_ascii (copy);
1ee5d538
KH
164 size -= VECSIZE (struct Lisp_Char_Table) - 1;
165 for (i = 0; i < size; i++)
166 XCHAR_TABLE (copy)->extras[i] = XCHAR_TABLE (table)->extras[i];
167
168 XSETCHAR_TABLE (copy, XCHAR_TABLE (copy));
169 return copy;
170}
171
172Lisp_Object
971de7fb 173sub_char_table_ref (Lisp_Object table, int c)
1ee5d538
KH
174{
175 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
176 int depth = XINT (tbl->depth);
177 int min_char = XINT (tbl->min_char);
178 Lisp_Object val;
179
180 val = tbl->contents[CHARTAB_IDX (c, depth, min_char)];
181 if (SUB_CHAR_TABLE_P (val))
182 val = sub_char_table_ref (val, c);
183 return val;
184}
185
186Lisp_Object
971de7fb 187char_table_ref (Lisp_Object table, int c)
1ee5d538
KH
188{
189 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
190 Lisp_Object val;
191
192 if (ASCII_CHAR_P (c))
193 {
194 val = tbl->ascii;
195 if (SUB_CHAR_TABLE_P (val))
196 val = XSUB_CHAR_TABLE (val)->contents[c];
197 }
198 else
199 {
200 val = tbl->contents[CHARTAB_IDX (c, 0, 0)];
201 if (SUB_CHAR_TABLE_P (val))
202 val = sub_char_table_ref (val, c);
203 }
204 if (NILP (val))
205 {
206 val = tbl->defalt;
207 if (NILP (val) && CHAR_TABLE_P (tbl->parent))
208 val = char_table_ref (tbl->parent, c);
209 }
210 return val;
8f924df7 211}
1ee5d538
KH
212
213static Lisp_Object
971de7fb 214sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to, Lisp_Object defalt)
1ee5d538
KH
215{
216 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
217 int depth = XINT (tbl->depth);
218 int min_char = XINT (tbl->min_char);
e15009d9 219 int max_char = min_char + chartab_chars[depth - 1] - 1;
7ef1f5d1 220 int index = CHARTAB_IDX (c, depth, min_char), idx;
1ee5d538 221 Lisp_Object val;
8f924df7 222
e15009d9 223 val = tbl->contents[index];
e15009d9
KH
224 if (SUB_CHAR_TABLE_P (val))
225 val = sub_char_table_ref_and_range (val, c, from, to, defalt);
226 else if (NILP (val))
227 val = defalt;
228
7ef1f5d1
KH
229 idx = index;
230 while (idx > 0 && *from < min_char + idx * chartab_chars[depth])
1ee5d538 231 {
e15009d9 232 Lisp_Object this_val;
e15009d9 233
7ef1f5d1
KH
234 c = min_char + idx * chartab_chars[depth] - 1;
235 idx--;
236 this_val = tbl->contents[idx];
e15009d9 237 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 238 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt);
e15009d9
KH
239 else if (NILP (this_val))
240 this_val = defalt;
241
242 if (! EQ (this_val, val))
7ef1f5d1
KH
243 {
244 *from = c + 1;
245 break;
246 }
1ee5d538 247 }
05756f21 248 while ((c = min_char + (index + 1) * chartab_chars[depth]) <= max_char
7ef1f5d1 249 && *to >= c)
1ee5d538 250 {
e15009d9 251 Lisp_Object this_val;
e15009d9
KH
252
253 index++;
254 this_val = tbl->contents[index];
255 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 256 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt);
e15009d9
KH
257 else if (NILP (this_val))
258 this_val = defalt;
259 if (! EQ (this_val, val))
7ef1f5d1
KH
260 {
261 *to = c - 1;
262 break;
263 }
1ee5d538 264 }
e15009d9 265
1ee5d538
KH
266 return val;
267}
268
269
7ef1f5d1
KH
270/* Return the value for C in char-table TABLE. Shrink the range *FROM
271 and *TO to cover characters (containing C) that have the same value
272 as C. It is not assured that the values of (*FROM - 1) and (*TO +
273 1) are different from that of C. */
e15009d9 274
1ee5d538 275Lisp_Object
971de7fb 276char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
1ee5d538
KH
277{
278 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
7ef1f5d1 279 int index = CHARTAB_IDX (c, 0, 0), idx;
1ee5d538
KH
280 Lisp_Object val;
281
e15009d9 282 val = tbl->contents[index];
7ef1f5d1
KH
283 if (*from < 0)
284 *from = 0;
285 if (*to < 0)
286 *to = MAX_CHAR;
e15009d9
KH
287 if (SUB_CHAR_TABLE_P (val))
288 val = sub_char_table_ref_and_range (val, c, from, to, tbl->defalt);
289 else if (NILP (val))
290 val = tbl->defalt;
291
7ef1f5d1
KH
292 idx = index;
293 while (*from < idx * chartab_chars[0])
1ee5d538 294 {
e15009d9 295 Lisp_Object this_val;
e15009d9 296
7ef1f5d1
KH
297 c = idx * chartab_chars[0] - 1;
298 idx--;
299 this_val = tbl->contents[idx];
e15009d9 300 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 301 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
e15009d9
KH
302 tbl->defalt);
303 else if (NILP (this_val))
304 this_val = tbl->defalt;
305
306 if (! EQ (this_val, val))
7ef1f5d1
KH
307 {
308 *from = c + 1;
309 break;
310 }
1ee5d538 311 }
7ef1f5d1 312 while (*to >= (index + 1) * chartab_chars[0])
1ee5d538 313 {
e15009d9 314 Lisp_Object this_val;
e15009d9
KH
315
316 index++;
7ef1f5d1 317 c = index * chartab_chars[0];
e15009d9
KH
318 this_val = tbl->contents[index];
319 if (SUB_CHAR_TABLE_P (this_val))
7ef1f5d1 320 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
e15009d9
KH
321 tbl->defalt);
322 else if (NILP (this_val))
323 this_val = tbl->defalt;
324 if (! EQ (this_val, val))
7ef1f5d1
KH
325 {
326 *to = c - 1;
327 break;
328 }
1ee5d538
KH
329 }
330
1ee5d538 331 return val;
e15009d9 332}
1ee5d538
KH
333
334
335#define ASET_RANGE(ARRAY, FROM, TO, LIMIT, VAL) \
336 do { \
337 int limit = (TO) < (LIMIT) ? (TO) : (LIMIT); \
338 for (; (FROM) < limit; (FROM)++) (ARRAY)->contents[(FROM)] = (VAL); \
339 } while (0)
340
341#define GET_SUB_CHAR_TABLE(TABLE, SUBTABLE, IDX, DEPTH, MIN_CHAR) \
342 do { \
343 (SUBTABLE) = (TABLE)->contents[(IDX)]; \
344 if (!SUB_CHAR_TABLE_P (SUBTABLE)) \
345 (SUBTABLE) = make_sub_char_table ((DEPTH), (MIN_CHAR), (SUBTABLE)); \
346 } while (0)
347
348
349static void
971de7fb 350sub_char_table_set (Lisp_Object table, int c, Lisp_Object val)
1ee5d538
KH
351{
352 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
353 int depth = XINT ((tbl)->depth);
354 int min_char = XINT ((tbl)->min_char);
355 int i = CHARTAB_IDX (c, depth, min_char);
356 Lisp_Object sub;
8f924df7 357
1ee5d538
KH
358 if (depth == 3)
359 tbl->contents[i] = val;
360 else
361 {
362 sub = tbl->contents[i];
363 if (! SUB_CHAR_TABLE_P (sub))
364 {
365 sub = make_sub_char_table (depth + 1,
366 min_char + i * chartab_chars[depth], sub);
367 tbl->contents[i] = sub;
368 }
369 sub_char_table_set (sub, c, val);
370 }
371}
372
373Lisp_Object
971de7fb 374char_table_set (Lisp_Object table, int c, Lisp_Object val)
1ee5d538
KH
375{
376 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
377
378 if (ASCII_CHAR_P (c)
379 && SUB_CHAR_TABLE_P (tbl->ascii))
380 {
381 XSUB_CHAR_TABLE (tbl->ascii)->contents[c] = val;
382 }
383 else
384 {
385 int i = CHARTAB_IDX (c, 0, 0);
386 Lisp_Object sub;
387
388 sub = tbl->contents[i];
389 if (! SUB_CHAR_TABLE_P (sub))
390 {
391 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
392 tbl->contents[i] = sub;
393 }
394 sub_char_table_set (sub, c, val);
395 if (ASCII_CHAR_P (c))
40033db7 396 tbl->ascii = char_table_ascii (table);
1ee5d538
KH
397 }
398 return val;
399}
400
401static void
971de7fb 402sub_char_table_set_range (Lisp_Object *table, int depth, int min_char, int from, int to, Lisp_Object val)
1ee5d538
KH
403{
404 int max_char = min_char + chartab_chars[depth] - 1;
405
ed09a18b 406 if (depth == 3 || (from <= min_char && to >= max_char))
1ee5d538
KH
407 *table = val;
408 else
409 {
410 int i, j;
411
412 depth++;
413 if (! SUB_CHAR_TABLE_P (*table))
414 *table = make_sub_char_table (depth, min_char, *table);
415 if (from < min_char)
416 from = min_char;
417 if (to > max_char)
418 to = max_char;
22d49f94 419 i = CHARTAB_IDX (from, depth, min_char);
1ee5d538 420 j = CHARTAB_IDX (to, depth, min_char);
22d49f94
KH
421 min_char += chartab_chars[depth] * i;
422 for (; i <= j; i++, min_char += chartab_chars[depth])
1ee5d538 423 sub_char_table_set_range (XSUB_CHAR_TABLE (*table)->contents + i,
22d49f94 424 depth, min_char, from, to, val);
1ee5d538
KH
425 }
426}
427
428
429Lisp_Object
971de7fb 430char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val)
1ee5d538
KH
431{
432 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
433 Lisp_Object *contents = tbl->contents;
434 int i, min_char;
435
436 if (from == to)
437 char_table_set (table, from, val);
438 else
439 {
440 for (i = CHARTAB_IDX (from, 0, 0), min_char = i * chartab_chars[0];
441 min_char <= to;
442 i++, min_char += chartab_chars[0])
443 sub_char_table_set_range (contents + i, 0, min_char, from, to, val);
444 if (ASCII_CHAR_P (from))
40033db7 445 tbl->ascii = char_table_ascii (table);
1ee5d538
KH
446 }
447 return val;
448}
449
450\f
451DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
452 1, 1, 0,
453 doc: /*
454Return the subtype of char-table CHAR-TABLE. The value is a symbol. */)
455 (char_table)
456 Lisp_Object char_table;
457{
458 CHECK_CHAR_TABLE (char_table);
459
460 return XCHAR_TABLE (char_table)->purpose;
461}
462
463DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
464 1, 1, 0,
465 doc: /* Return the parent char-table of CHAR-TABLE.
466The value is either nil or another char-table.
467If CHAR-TABLE holds nil for a given character,
468then the actual applicable value is inherited from the parent char-table
469\(or from its parents, if necessary). */)
470 (char_table)
471 Lisp_Object char_table;
472{
473 CHECK_CHAR_TABLE (char_table);
474
475 return XCHAR_TABLE (char_table)->parent;
476}
477
478DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
479 2, 2, 0,
480 doc: /* Set the parent char-table of CHAR-TABLE to PARENT.
6b61353c 481Return PARENT. PARENT must be either nil or another char-table. */)
1ee5d538
KH
482 (char_table, parent)
483 Lisp_Object char_table, parent;
484{
485 Lisp_Object temp;
486
487 CHECK_CHAR_TABLE (char_table);
488
489 if (!NILP (parent))
490 {
491 CHECK_CHAR_TABLE (parent);
492
493 for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
494 if (EQ (temp, char_table))
495 error ("Attempt to make a chartable be its own parent");
496 }
497
498 XCHAR_TABLE (char_table)->parent = parent;
499
500 return parent;
501}
502
503DEFUN ("char-table-extra-slot", Fchar_table_extra_slot, Schar_table_extra_slot,
504 2, 2, 0,
505 doc: /* Return the value of CHAR-TABLE's extra-slot number N. */)
506 (char_table, n)
507 Lisp_Object char_table, n;
508{
509 CHECK_CHAR_TABLE (char_table);
510 CHECK_NUMBER (n);
511 if (XINT (n) < 0
512 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
513 args_out_of_range (char_table, n);
514
515 return XCHAR_TABLE (char_table)->extras[XINT (n)];
516}
517
518DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
519 Sset_char_table_extra_slot,
520 3, 3, 0,
521 doc: /* Set CHAR-TABLE's extra-slot number N to VALUE. */)
522 (char_table, n, value)
523 Lisp_Object char_table, n, value;
524{
525 CHECK_CHAR_TABLE (char_table);
526 CHECK_NUMBER (n);
527 if (XINT (n) < 0
528 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
529 args_out_of_range (char_table, n);
530
531 return XCHAR_TABLE (char_table)->extras[XINT (n)] = value;
532}
533\f
534DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
535 2, 2, 0,
536 doc: /* Return the value in CHAR-TABLE for a range of characters RANGE.
537RANGE should be nil (for the default value),
538a cons of character codes (for characters in the range), or a character code. */)
539 (char_table, range)
540 Lisp_Object char_table, range;
541{
542 Lisp_Object val;
543 CHECK_CHAR_TABLE (char_table);
544
545 if (EQ (range, Qnil))
546 val = XCHAR_TABLE (char_table)->defalt;
547 else if (INTEGERP (range))
548 val = CHAR_TABLE_REF (char_table, XINT (range));
549 else if (CONSP (range))
550 {
551 int from, to;
552
8f924df7
KH
553 CHECK_CHARACTER_CAR (range);
554 CHECK_CHARACTER_CDR (range);
1ee5d538
KH
555 val = char_table_ref_and_range (char_table, XINT (XCAR (range)),
556 &from, &to);
557 /* Not yet implemented. */
558 }
559 else
560 error ("Invalid RANGE argument to `char-table-range'");
561 return val;
562}
563
564DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
565 3, 3, 0,
6b61353c 566 doc: /* Set the value in CHAR-TABLE for a range of characters RANGE to VALUE.
1ee5d538 567RANGE should be t (for all characters), nil (for the default value),
6b61353c
KH
568a cons of character codes (for characters in the range),
569or a character code. Return VALUE. */)
1ee5d538
KH
570 (char_table, range, value)
571 Lisp_Object char_table, range, value;
572{
573 CHECK_CHAR_TABLE (char_table);
574 if (EQ (range, Qt))
575 {
576 int i;
577
c6bff69e 578 XCHAR_TABLE (char_table)->ascii = value;
1ee5d538 579 for (i = 0; i < chartab_size[0]; i++)
c6bff69e 580 XCHAR_TABLE (char_table)->contents[i] = value;
1ee5d538
KH
581 }
582 else if (EQ (range, Qnil))
583 XCHAR_TABLE (char_table)->defalt = value;
584 else if (INTEGERP (range))
585 char_table_set (char_table, XINT (range), value);
586 else if (CONSP (range))
587 {
8f924df7
KH
588 CHECK_CHARACTER_CAR (range);
589 CHECK_CHARACTER_CDR (range);
1ee5d538
KH
590 char_table_set_range (char_table,
591 XINT (XCAR (range)), XINT (XCDR (range)), value);
592 }
593 else
594 error ("Invalid RANGE argument to `set-char-table-range'");
595
596 return value;
597}
598
599DEFUN ("set-char-table-default", Fset_char_table_default,
600 Sset_char_table_default, 3, 3, 0,
601 doc: /*
f6e5cae0 602This function is obsolete and has no effect. */)
1ee5d538
KH
603 (char_table, ch, value)
604 Lisp_Object char_table, ch, value;
605{
606 return Qnil;
607}
608
609/* Look up the element in TABLE at index CH, and return it as an
05d6275c 610 integer. If the element is not a character, return CH itself. */
1ee5d538
KH
611
612int
971de7fb 613char_table_translate (Lisp_Object table, int ch)
1ee5d538
KH
614{
615 Lisp_Object value;
616 value = Faref (table, make_number (ch));
05d6275c 617 if (! CHARACTERP (value))
1ee5d538
KH
618 return ch;
619 return XINT (value);
620}
621
622static Lisp_Object
971de7fb 623optimize_sub_char_table (Lisp_Object table, Lisp_Object test)
1ee5d538
KH
624{
625 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
626 int depth = XINT (tbl->depth);
627 Lisp_Object elt, this;
c3b57f23 628 int i, optimizable;
1ee5d538
KH
629
630 elt = XSUB_CHAR_TABLE (table)->contents[0];
631 if (SUB_CHAR_TABLE_P (elt))
d0827857
SM
632 elt = XSUB_CHAR_TABLE (table)->contents[0]
633 = optimize_sub_char_table (elt, test);
c3b57f23 634 optimizable = SUB_CHAR_TABLE_P (elt) ? 0 : 1;
1ee5d538
KH
635 for (i = 1; i < chartab_size[depth]; i++)
636 {
637 this = XSUB_CHAR_TABLE (table)->contents[i];
638 if (SUB_CHAR_TABLE_P (this))
639 this = XSUB_CHAR_TABLE (table)->contents[i]
d0827857 640 = optimize_sub_char_table (this, test);
c3b57f23
KH
641 if (optimizable
642 && (NILP (test) ? NILP (Fequal (this, elt)) /* defaults to `equal'. */
d0827857
SM
643 : EQ (test, Qeq) ? !EQ (this, elt) /* Optimize `eq' case. */
644 : NILP (call2 (test, this, elt))))
c3b57f23 645 optimizable = 0;
1ee5d538
KH
646 }
647
c3b57f23 648 return (optimizable ? elt : table);
1ee5d538
KH
649}
650
651DEFUN ("optimize-char-table", Foptimize_char_table, Soptimize_char_table,
d0827857
SM
652 1, 2, 0,
653 doc: /* Optimize CHAR-TABLE.
654TEST is the comparison function used to decide whether two entries are
655equivalent and can be merged. It defaults to `equal'. */)
656 (char_table, test)
657 Lisp_Object char_table, test;
1ee5d538
KH
658{
659 Lisp_Object elt;
660 int i;
661
662 CHECK_CHAR_TABLE (char_table);
663
664 for (i = 0; i < chartab_size[0]; i++)
665 {
666 elt = XCHAR_TABLE (char_table)->contents[i];
667 if (SUB_CHAR_TABLE_P (elt))
d0827857
SM
668 XCHAR_TABLE (char_table)->contents[i]
669 = optimize_sub_char_table (elt, test);
1ee5d538 670 }
4d632321
SM
671 /* Reset the `ascii' cache, in case it got optimized away. */
672 XCHAR_TABLE (char_table)->ascii = char_table_ascii (char_table);
673
1ee5d538
KH
674 return Qnil;
675}
676
677\f
57d53d1b
KH
678/* Map C_FUNCTION or FUNCTION over TABLE (top or sub char-table),
679 calling it for each character or group of characters that share a
680 value. RANGE is a cons (FROM . TO) specifying the range of target
681 characters, VAL is a value of FROM in TABLE, DEFAULT_VAL is the
682 default value of the char-table, PARENT is the parent of the
683 char-table.
684
685 ARG is passed to C_FUNCTION when that is called.
686
687 It returns the value of last character covered by TABLE (not the
688 value inheritted from the parent), and by side-effect, the car part
689 of RANGE is updated to the minimum character C where C and all the
690 following characters in TABLE have the same value. */
691
1ee5d538 692static Lisp_Object
dd4c5104
DN
693map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
694 Lisp_Object function, Lisp_Object table, Lisp_Object arg, Lisp_Object val,
695 Lisp_Object range, Lisp_Object default_val, Lisp_Object parent)
1ee5d538 696{
57d53d1b
KH
697 /* Pointer to the elements of TABLE. */
698 Lisp_Object *contents;
699 /* Depth of TABLE. */
700 int depth;
701 /* Minimum and maxinum characters covered by TABLE. */
702 int min_char, max_char;
703 /* Number of characters covered by one element of TABLE. */
704 int chars_in_block;
705 int from = XINT (XCAR (range)), to = XINT (XCDR (range));
1ee5d538
KH
706 int i, c;
707
57d53d1b
KH
708 if (SUB_CHAR_TABLE_P (table))
709 {
710 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
711
712 depth = XINT (tbl->depth);
713 contents = tbl->contents;
714 min_char = XINT (tbl->min_char);
715 max_char = min_char + chartab_chars[depth - 1] - 1;
716 }
717 else
718 {
719 depth = 0;
720 contents = XCHAR_TABLE (table)->contents;
721 min_char = 0;
722 max_char = MAX_CHAR;
723 }
724 chars_in_block = chartab_chars[depth];
725
726 if (to < max_char)
727 max_char = to;
728 /* Set I to the index of the first element to check. */
729 if (from <= min_char)
730 i = 0;
731 else
732 i = (from - min_char) / chars_in_block;
733 for (c = min_char + chars_in_block * i; c <= max_char;
734 i++, c += chars_in_block)
1ee5d538 735 {
57d53d1b
KH
736 Lisp_Object this = contents[i];
737 int nextc = c + chars_in_block;
1ee5d538 738
1ee5d538 739 if (SUB_CHAR_TABLE_P (this))
57d53d1b
KH
740 {
741 if (to >= nextc)
742 XSETCDR (range, make_number (nextc - 1));
743 val = map_sub_char_table (c_function, function, this, arg,
744 val, range, default_val, parent);
745 }
2f76e15e 746 else
1ee5d538 747 {
2f76e15e
KH
748 if (NILP (this))
749 this = default_val;
d0827857 750 if (!EQ (val, this))
1ee5d538 751 {
57d53d1b
KH
752 int different_value = 1;
753
754 if (NILP (val))
755 {
756 if (! NILP (parent))
757 {
758 Lisp_Object temp = XCHAR_TABLE (parent)->parent;
759
760 /* This is to get a value of FROM in PARENT
761 without checking the parent of PARENT. */
762 XCHAR_TABLE (parent)->parent = Qnil;
763 val = CHAR_TABLE_REF (parent, from);
764 XCHAR_TABLE (parent)->parent = temp;
765 XSETCDR (range, make_number (c - 1));
766 val = map_sub_char_table (c_function, function,
767 parent, arg, val, range,
768 XCHAR_TABLE (parent)->defalt,
769 XCHAR_TABLE (parent)->parent);
d0827857 770 if (EQ (val, this))
57d53d1b
KH
771 different_value = 0;
772 }
773 }
774 if (! NILP (val) && different_value)
1ee5d538 775 {
8f924df7 776 XSETCDR (range, make_number (c - 1));
0a4bacdc 777 if (EQ (XCAR (range), XCDR (range)))
2f76e15e
KH
778 {
779 if (c_function)
780 (*c_function) (arg, XCAR (range), val);
781 else
782 call2 (function, XCAR (range), val);
783 }
1ee5d538 784 else
2f76e15e
KH
785 {
786 if (c_function)
787 (*c_function) (arg, range, val);
788 else
789 call2 (function, range, val);
790 }
1ee5d538 791 }
2f76e15e 792 val = this;
57d53d1b 793 from = c;
8f924df7 794 XSETCAR (range, make_number (c));
1ee5d538 795 }
1ee5d538 796 }
57d53d1b 797 XSETCDR (range, make_number (to));
1ee5d538
KH
798 }
799 return val;
800}
801
802
803/* Map C_FUNCTION or FUNCTION over TABLE, calling it for each
804 character or group of characters that share a value.
805
8f924df7 806 ARG is passed to C_FUNCTION when that is called. */
1ee5d538
KH
807
808void
971de7fb 809map_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object), Lisp_Object function, Lisp_Object table, Lisp_Object arg)
1ee5d538
KH
810{
811 Lisp_Object range, val;
239191f2 812 struct gcpro gcpro1, gcpro2, gcpro3;
1ee5d538 813
57d53d1b 814 range = Fcons (make_number (0), make_number (MAX_CHAR));
239191f2 815 GCPRO3 (table, arg, range);
2f76e15e
KH
816 val = XCHAR_TABLE (table)->ascii;
817 if (SUB_CHAR_TABLE_P (val))
818 val = XSUB_CHAR_TABLE (val)->contents[0];
57d53d1b
KH
819 val = map_sub_char_table (c_function, function, table, arg, val, range,
820 XCHAR_TABLE (table)->defalt,
821 XCHAR_TABLE (table)->parent);
822 /* If VAL is nil and TABLE has a parent, we must consult the parent
823 recursively. */
824 while (NILP (val) && ! NILP (XCHAR_TABLE (table)->parent))
1ee5d538 825 {
57d53d1b
KH
826 Lisp_Object parent = XCHAR_TABLE (table)->parent;
827 Lisp_Object temp = XCHAR_TABLE (parent)->parent;
828 int from = XINT (XCAR (range));
829
830 /* This is to get a value of FROM in PARENT without checking the
831 parent of PARENT. */
832 XCHAR_TABLE (parent)->parent = Qnil;
833 val = CHAR_TABLE_REF (parent, from);
834 XCHAR_TABLE (parent)->parent = temp;
835 val = map_sub_char_table (c_function, function, parent, arg, val, range,
836 XCHAR_TABLE (parent)->defalt,
837 XCHAR_TABLE (parent)->parent);
838 table = parent;
1ee5d538 839 }
2f76e15e
KH
840
841 if (! NILP (val))
842 {
0a4bacdc
KH
843 if (EQ (XCAR (range), XCDR (range)))
844 {
845 if (c_function)
846 (*c_function) (arg, XCAR (range), val);
847 else
848 call2 (function, XCAR (range), val);
849 }
2f76e15e 850 else
0a4bacdc
KH
851 {
852 if (c_function)
853 (*c_function) (arg, range, val);
854 else
855 call2 (function, range, val);
856 }
2f76e15e 857 }
26132fb5
AS
858
859 UNGCPRO;
1ee5d538
KH
860}
861
862DEFUN ("map-char-table", Fmap_char_table, Smap_char_table,
863 2, 2, 0,
864 doc: /*
ed7219f8 865Call FUNCTION for each character in CHAR-TABLE that has non-nil value.
1ee5d538 866FUNCTION is called with two arguments--a key and a value.
2f76e15e
KH
867The key is a character code or a cons of character codes specifying a
868range of characters that have the same value. */)
1ee5d538
KH
869 (function, char_table)
870 Lisp_Object function, char_table;
871{
872 CHECK_CHAR_TABLE (char_table);
873
8f924df7 874 map_char_table (NULL, function, char_table, char_table);
1ee5d538
KH
875 return Qnil;
876}
877
e15009d9
KH
878
879static void
dd4c5104
DN
880map_sub_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Object),
881 Lisp_Object function, Lisp_Object table, Lisp_Object arg,
882 Lisp_Object range, struct charset *charset,
883 unsigned from, unsigned to)
e15009d9
KH
884{
885 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
886 int depth = XINT (tbl->depth);
887 int c, i;
888
889 if (depth < 3)
890 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth];
891 i++, c += chartab_chars[depth])
892 {
893 Lisp_Object this;
894
895 this = tbl->contents[i];
896 if (SUB_CHAR_TABLE_P (this))
897 map_sub_char_table_for_charset (c_function, function, this, arg,
898 range, charset, from, to);
899 else
900 {
901 if (! NILP (XCAR (range)))
902 {
903 XSETCDR (range, make_number (c - 1));
904 if (c_function)
905 (*c_function) (arg, range);
906 else
907 call2 (function, range, arg);
908 }
909 XSETCAR (range, Qnil);
910 }
911 }
912 else
913 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth]; i++, c ++)
914 {
915 Lisp_Object this;
916 unsigned code;
917
918 this = tbl->contents[i];
919 if (NILP (this)
920 || (charset
921 && (code = ENCODE_CHAR (charset, c),
922 (code < from || code > to))))
923 {
924 if (! NILP (XCAR (range)))
925 {
926 XSETCDR (range, make_number (c - 1));
927 if (c_function)
bc85ac78 928 (*c_function) (arg, range);
e15009d9
KH
929 else
930 call2 (function, range, arg);
931 XSETCAR (range, Qnil);
932 }
933 }
934 else
935 {
936 if (NILP (XCAR (range)))
937 XSETCAR (range, make_number (c));
938 }
939 }
940}
941
942
a6805333 943/* Support function for `map-charset-chars'. Map C_FUNCTION or
60612c8f 944 FUNCTION over TABLE, calling it for each character or a group of
a6805333
KH
945 succeeding characters that have non-nil value in TABLE. TABLE is a
946 "mapping table" or a "deunifier table" of a certain charset.
947
948 If CHARSET is not NULL (this is the case that `map-charset-chars'
949 is called with non-nil FROM-CODE and TO-CODE), it is a charset who
950 owns TABLE, and the function is called only on a character in the
951 range FROM and TO. FROM and TO are not character codes, but code
952 points of a character in CHARSET.
953
954 This function is called in these two cases:
955
956 (1) A charset has a mapping file name in :map property.
957
958 (2) A charset has an upper code space in :offset property and a
959 mapping file name in :unify-map property. In this case, this
960 function is called only for characters in the Unicode code space.
961 Characters in upper code space are handled directly in
962 map_charset_chars. */
963
e15009d9 964void
dd4c5104
DN
965map_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Object),
966 Lisp_Object function, Lisp_Object table, Lisp_Object arg,
967 struct charset *charset,
968 unsigned from, unsigned to)
e15009d9
KH
969{
970 Lisp_Object range;
971 int c, i;
26132fb5 972 struct gcpro gcpro1;
e15009d9 973
8f924df7 974 range = Fcons (Qnil, Qnil);
26132fb5 975 GCPRO1 (range);
e15009d9
KH
976
977 for (i = 0, c = 0; i < chartab_size[0]; i++, c += chartab_chars[0])
978 {
979 Lisp_Object this;
980
981 this = XCHAR_TABLE (table)->contents[i];
982 if (SUB_CHAR_TABLE_P (this))
983 map_sub_char_table_for_charset (c_function, function, this, arg,
984 range, charset, from, to);
985 else
986 {
987 if (! NILP (XCAR (range)))
988 {
989 XSETCDR (range, make_number (c - 1));
990 if (c_function)
991 (*c_function) (arg, range);
992 else
993 call2 (function, range, arg);
994 }
995 XSETCAR (range, Qnil);
996 }
997 }
998 if (! NILP (XCAR (range)))
999 {
1000 XSETCDR (range, make_number (c - 1));
1001 if (c_function)
1002 (*c_function) (arg, range);
1003 else
1004 call2 (function, range, arg);
1005 }
26132fb5
AS
1006
1007 UNGCPRO;
e15009d9
KH
1008}
1009
1ee5d538
KH
1010\f
1011void
971de7fb 1012syms_of_chartab (void)
1ee5d538
KH
1013{
1014 defsubr (&Smake_char_table);
1015 defsubr (&Schar_table_parent);
1016 defsubr (&Schar_table_subtype);
1017 defsubr (&Sset_char_table_parent);
1018 defsubr (&Schar_table_extra_slot);
1019 defsubr (&Sset_char_table_extra_slot);
1020 defsubr (&Schar_table_range);
1021 defsubr (&Sset_char_table_range);
1022 defsubr (&Sset_char_table_default);
1023 defsubr (&Soptimize_char_table);
1024 defsubr (&Smap_char_table);
1025}
fbaf0946
MB
1026
1027/* arch-tag: 18b5b560-7ab5-4108-b09e-d5dd65dc6fda
1028 (do not change this comment) */