*** empty log message ***
[bpt/emacs.git] / src / chartab.c
CommitLineData
1ee5d538
KH
1/* chartab.c -- char-table support
2 Copyright (C) 2001, 2002
3 National Institute of Advanced Industrial Science and Technology (AIST)
4 Registration Number H13PRO009
5
6This file is part of GNU Emacs.
7
8GNU Emacs is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
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
19along with GNU Emacs; see the file COPYING. If not, write to
20the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21Boston, MA 02111-1307, USA. */
22
23#include <config.h>
b4a12c67
DL
24#include "lisp.h"
25#include "character.h"
26#include "charset.h"
27#include "ccl.h"
1ee5d538
KH
28
29/* 64/16/32/128 */
30
31/* Number of elements in Nth level char-table. */
32const int chartab_size[4] =
33 { (1 << CHARTAB_SIZE_BITS_0),
34 (1 << CHARTAB_SIZE_BITS_1),
35 (1 << CHARTAB_SIZE_BITS_2),
36 (1 << CHARTAB_SIZE_BITS_3) };
37
38/* Number of characters each element of Nth level char-table
39 covers. */
40const int chartab_chars[4] =
41 { (1 << (CHARTAB_SIZE_BITS_1 + CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3)),
42 (1 << (CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3)),
43 (1 << CHARTAB_SIZE_BITS_3),
44 1 };
45
46/* Number of characters (in bits) each element of Nth level char-table
47 covers. */
48const int chartab_bits[4] =
49 { (CHARTAB_SIZE_BITS_1 + CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3),
50 (CHARTAB_SIZE_BITS_2 + CHARTAB_SIZE_BITS_3),
51 CHARTAB_SIZE_BITS_3,
52 0 };
53
54#define CHARTAB_IDX(c, depth, min_char) \
55 (((c) - (min_char)) >> chartab_bits[(depth)])
56
57
58DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0,
eaa3b0e0 59 doc: /* Return a newly created char-table, with purpose PURPOSE.
1ee5d538
KH
60Each element is initialized to INIT, which defaults to nil.
61
eaa3b0e0
KH
62PURPOSE should be a symbol. If it has a `char-table-extra-slots'
63property, the property's value should be an integer between 0 and 10
64that specifies how many extra slots the char-table has. Otherwise,
65the char-table has no extra slot. */)
1ee5d538
KH
66 (purpose, init)
67 register Lisp_Object purpose, init;
68{
69 Lisp_Object vector;
70 Lisp_Object n;
eaa3b0e0 71 int n_extras;
1ee5d538
KH
72 int size;
73
74 CHECK_SYMBOL (purpose);
eaa3b0e0
KH
75 n = Fget (purpose, Qchar_table_extra_slots);
76 if (NILP (n))
77 n_extras = 0;
78 else
1ee5d538 79 {
eaa3b0e0
KH
80 CHECK_NATNUM (n);
81 n_extras = XINT (n);
82 if (n_extras > 10)
83 args_out_of_range (n, Qnil);
1ee5d538
KH
84 }
85
86 size = VECSIZE (struct Lisp_Char_Table) - 1 + n_extras;
87 vector = Fmake_vector (make_number (size), init);
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
95make_sub_char_table (depth, min_char, defalt)
96 int depth, min_char;
97 Lisp_Object defalt;
98{
99 Lisp_Object table;
100 int size = VECSIZE (struct Lisp_Sub_Char_Table) - 1 + chartab_size[depth];
1ee5d538
KH
101
102 table = Fmake_vector (make_number (size), defalt);
103 XSUB_CHAR_TABLE (table)->depth = make_number (depth);
104 XSUB_CHAR_TABLE (table)->min_char = make_number (min_char);
105 XSETSUB_CHAR_TABLE (table, XSUB_CHAR_TABLE (table));
106
107 return table;
108}
109
110static Lisp_Object
111char_table_ascii (table)
112 Lisp_Object table;
113{
114 Lisp_Object sub;
115
116 sub = XCHAR_TABLE (table)->contents[0];
117 sub = XSUB_CHAR_TABLE (sub)->contents[0];
118 return XSUB_CHAR_TABLE (sub)->contents[0];
119}
120
121Lisp_Object
122copy_sub_char_table (table)
123 Lisp_Object table;
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
147copy_char_table (table)
148 Lisp_Object table;
149{
150 Lisp_Object copy;
151 int size = XCHAR_TABLE (table)->size & PSEUDOVECTOR_SIZE_MASK;
152 int i;
153
154 copy = Fmake_vector (make_number (size), Qnil);
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;
158 XCHAR_TABLE (copy)->ascii = XCHAR_TABLE (table)->ascii;
159 for (i = 0; i < chartab_size[0]; i++)
160 XCHAR_TABLE (copy)->contents[i]
161 = (SUB_CHAR_TABLE_P (XCHAR_TABLE (table)->contents[i])
162 ? copy_sub_char_table (XCHAR_TABLE (table)->contents[i])
163 : XCHAR_TABLE (table)->contents[i]);
164 if (SUB_CHAR_TABLE_P (XCHAR_TABLE (copy)->ascii))
165 XCHAR_TABLE (copy)->ascii = char_table_ascii (copy);
166 size -= VECSIZE (struct Lisp_Char_Table) - 1;
167 for (i = 0; i < size; i++)
168 XCHAR_TABLE (copy)->extras[i] = XCHAR_TABLE (table)->extras[i];
169
170 XSETCHAR_TABLE (copy, XCHAR_TABLE (copy));
171 return copy;
172}
173
174Lisp_Object
175sub_char_table_ref (table, c)
176 Lisp_Object table;
177 int c;
178{
179 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
180 int depth = XINT (tbl->depth);
181 int min_char = XINT (tbl->min_char);
182 Lisp_Object val;
183
184 val = tbl->contents[CHARTAB_IDX (c, depth, min_char)];
185 if (SUB_CHAR_TABLE_P (val))
186 val = sub_char_table_ref (val, c);
187 return val;
188}
189
190Lisp_Object
191char_table_ref (table, c)
192 Lisp_Object table;
193 int c;
194{
195 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
196 Lisp_Object val;
197
198 if (ASCII_CHAR_P (c))
199 {
200 val = tbl->ascii;
201 if (SUB_CHAR_TABLE_P (val))
202 val = XSUB_CHAR_TABLE (val)->contents[c];
203 }
204 else
205 {
206 val = tbl->contents[CHARTAB_IDX (c, 0, 0)];
207 if (SUB_CHAR_TABLE_P (val))
208 val = sub_char_table_ref (val, c);
209 }
210 if (NILP (val))
211 {
212 val = tbl->defalt;
213 if (NILP (val) && CHAR_TABLE_P (tbl->parent))
214 val = char_table_ref (tbl->parent, c);
215 }
216 return val;
217}
218
219static Lisp_Object
e15009d9 220sub_char_table_ref_and_range (table, c, from, to, defalt)
1ee5d538
KH
221 Lisp_Object table;
222 int c;
223 int *from, *to;
e15009d9 224 Lisp_Object defalt;
1ee5d538
KH
225{
226 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
227 int depth = XINT (tbl->depth);
228 int min_char = XINT (tbl->min_char);
e15009d9
KH
229 int max_char = min_char + chartab_chars[depth - 1] - 1;
230 int index = CHARTAB_IDX (c, depth, min_char);
1ee5d538
KH
231 Lisp_Object val;
232
e15009d9
KH
233 val = tbl->contents[index];
234 *from = min_char + index * chartab_chars[depth];
235 *to = *from + chartab_chars[depth] - 1;
236 if (SUB_CHAR_TABLE_P (val))
237 val = sub_char_table_ref_and_range (val, c, from, to, defalt);
238 else if (NILP (val))
239 val = defalt;
240
241 while (*from > min_char
242 && *from == min_char + index * chartab_chars[depth])
1ee5d538 243 {
e15009d9
KH
244 Lisp_Object this_val;
245 int this_from = *from - chartab_chars[depth];
246 int this_to = *from - 1;
247
248 index--;
249 this_val = tbl->contents[index];
250 if (SUB_CHAR_TABLE_P (this_val))
251 this_val = sub_char_table_ref_and_range (this_val, this_to,
252 &this_from, &this_to,
253 defalt);
254 else if (NILP (this_val))
255 this_val = defalt;
256
257 if (! EQ (this_val, val))
258 break;
259 *from = this_from;
1ee5d538 260 }
e15009d9
KH
261 index = CHARTAB_IDX (c, depth, min_char);
262 while (*to < max_char
263 && *to == min_char + (index + 1) * chartab_chars[depth] - 1)
1ee5d538 264 {
e15009d9
KH
265 Lisp_Object this_val;
266 int this_from = *to + 1;
267 int this_to = this_from + chartab_chars[depth] - 1;
268
269 index++;
270 this_val = tbl->contents[index];
271 if (SUB_CHAR_TABLE_P (this_val))
272 this_val = sub_char_table_ref_and_range (this_val, this_from,
273 &this_from, &this_to,
274 defalt);
275 else if (NILP (this_val))
276 this_val = defalt;
277 if (! EQ (this_val, val))
278 break;
279 *to = this_to;
1ee5d538 280 }
e15009d9 281
1ee5d538
KH
282 return val;
283}
284
285
e15009d9
KH
286/* Return the value for C in char-table TABLE. Set *FROM and *TO to
287 the range of characters (containing C) that have the same value as
288 C. It is not assured that the value of (*FROM - 1) and (*TO + 1)
289 is different from that of C. */
290
1ee5d538
KH
291Lisp_Object
292char_table_ref_and_range (table, c, from, to)
293 Lisp_Object table;
294 int c;
295 int *from, *to;
296{
297 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
e15009d9 298 int index = CHARTAB_IDX (c, 0, 0);
1ee5d538
KH
299 Lisp_Object val;
300
e15009d9
KH
301 val = tbl->contents[index];
302 *from = index * chartab_chars[0];
303 *to = *from + chartab_chars[0] - 1;
304 if (SUB_CHAR_TABLE_P (val))
305 val = sub_char_table_ref_and_range (val, c, from, to, tbl->defalt);
306 else if (NILP (val))
307 val = tbl->defalt;
308
309 while (*from > 0 && *from == index * chartab_chars[0])
1ee5d538 310 {
e15009d9
KH
311 Lisp_Object this_val;
312 int this_from = *from - chartab_chars[0];
313 int this_to = *from - 1;
314
315 index--;
316 this_val = tbl->contents[index];
317 if (SUB_CHAR_TABLE_P (this_val))
318 this_val = sub_char_table_ref_and_range (this_val, this_to,
319 &this_from, &this_to,
320 tbl->defalt);
321 else if (NILP (this_val))
322 this_val = tbl->defalt;
323
324 if (! EQ (this_val, val))
325 break;
326 *from = this_from;
1ee5d538 327 }
e15009d9 328 while (*to < MAX_CHAR && *to == (index + 1) * chartab_chars[0] - 1)
1ee5d538 329 {
e15009d9
KH
330 Lisp_Object this_val;
331 int this_from = *to + 1;
332 int this_to = this_from + chartab_chars[0] - 1;
333
334 index++;
335 this_val = tbl->contents[index];
336 if (SUB_CHAR_TABLE_P (this_val))
337 this_val = sub_char_table_ref_and_range (this_val, this_from,
338 &this_from, &this_to,
339 tbl->defalt);
340 else if (NILP (this_val))
341 this_val = tbl->defalt;
342 if (! EQ (this_val, val))
343 break;
344 *to = this_to;
1ee5d538
KH
345 }
346
1ee5d538 347 return val;
e15009d9 348}
1ee5d538
KH
349
350
351#define ASET_RANGE(ARRAY, FROM, TO, LIMIT, VAL) \
352 do { \
353 int limit = (TO) < (LIMIT) ? (TO) : (LIMIT); \
354 for (; (FROM) < limit; (FROM)++) (ARRAY)->contents[(FROM)] = (VAL); \
355 } while (0)
356
357#define GET_SUB_CHAR_TABLE(TABLE, SUBTABLE, IDX, DEPTH, MIN_CHAR) \
358 do { \
359 (SUBTABLE) = (TABLE)->contents[(IDX)]; \
360 if (!SUB_CHAR_TABLE_P (SUBTABLE)) \
361 (SUBTABLE) = make_sub_char_table ((DEPTH), (MIN_CHAR), (SUBTABLE)); \
362 } while (0)
363
364
365static void
366sub_char_table_set (table, c, val)
367 Lisp_Object table;
368 int c;
369 Lisp_Object val;
370{
371 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
372 int depth = XINT ((tbl)->depth);
373 int min_char = XINT ((tbl)->min_char);
374 int i = CHARTAB_IDX (c, depth, min_char);
375 Lisp_Object sub;
376
377 if (depth == 3)
378 tbl->contents[i] = val;
379 else
380 {
381 sub = tbl->contents[i];
382 if (! SUB_CHAR_TABLE_P (sub))
383 {
384 sub = make_sub_char_table (depth + 1,
385 min_char + i * chartab_chars[depth], sub);
386 tbl->contents[i] = sub;
387 }
388 sub_char_table_set (sub, c, val);
389 }
390}
391
392Lisp_Object
393char_table_set (table, c, val)
394 Lisp_Object table;
395 int c;
396 Lisp_Object val;
397{
398 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
399
400 if (ASCII_CHAR_P (c)
401 && SUB_CHAR_TABLE_P (tbl->ascii))
402 {
403 XSUB_CHAR_TABLE (tbl->ascii)->contents[c] = val;
404 }
405 else
406 {
407 int i = CHARTAB_IDX (c, 0, 0);
408 Lisp_Object sub;
409
410 sub = tbl->contents[i];
411 if (! SUB_CHAR_TABLE_P (sub))
412 {
413 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
414 tbl->contents[i] = sub;
415 }
416 sub_char_table_set (sub, c, val);
417 if (ASCII_CHAR_P (c))
418 tbl->ascii = char_table_ascii (tbl);
419 }
420 return val;
421}
422
423static void
424sub_char_table_set_range (table, depth, min_char, from, to, val)
425 Lisp_Object *table;
426 int depth;
427 int min_char;
428 int from, to;
429 Lisp_Object val;
430{
431 int max_char = min_char + chartab_chars[depth] - 1;
432
ed09a18b 433 if (depth == 3 || (from <= min_char && to >= max_char))
1ee5d538
KH
434 *table = val;
435 else
436 {
437 int i, j;
438
439 depth++;
440 if (! SUB_CHAR_TABLE_P (*table))
441 *table = make_sub_char_table (depth, min_char, *table);
442 if (from < min_char)
443 from = min_char;
444 if (to > max_char)
445 to = max_char;
22d49f94 446 i = CHARTAB_IDX (from, depth, min_char);
1ee5d538 447 j = CHARTAB_IDX (to, depth, min_char);
22d49f94
KH
448 min_char += chartab_chars[depth] * i;
449 for (; i <= j; i++, min_char += chartab_chars[depth])
1ee5d538 450 sub_char_table_set_range (XSUB_CHAR_TABLE (*table)->contents + i,
22d49f94 451 depth, min_char, from, to, val);
1ee5d538
KH
452 }
453}
454
455
456Lisp_Object
457char_table_set_range (table, from, to, val)
458 Lisp_Object table;
459 int from, to;
460 Lisp_Object val;
461{
462 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
463 Lisp_Object *contents = tbl->contents;
464 int i, min_char;
465
466 if (from == to)
467 char_table_set (table, from, val);
468 else
469 {
470 for (i = CHARTAB_IDX (from, 0, 0), min_char = i * chartab_chars[0];
471 min_char <= to;
472 i++, min_char += chartab_chars[0])
473 sub_char_table_set_range (contents + i, 0, min_char, from, to, val);
474 if (ASCII_CHAR_P (from))
475 tbl->ascii = char_table_ascii (tbl);
476 }
477 return val;
478}
479
480\f
481DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype,
482 1, 1, 0,
483 doc: /*
484Return the subtype of char-table CHAR-TABLE. The value is a symbol. */)
485 (char_table)
486 Lisp_Object char_table;
487{
488 CHECK_CHAR_TABLE (char_table);
489
490 return XCHAR_TABLE (char_table)->purpose;
491}
492
493DEFUN ("char-table-parent", Fchar_table_parent, Schar_table_parent,
494 1, 1, 0,
495 doc: /* Return the parent char-table of CHAR-TABLE.
496The value is either nil or another char-table.
497If CHAR-TABLE holds nil for a given character,
498then the actual applicable value is inherited from the parent char-table
499\(or from its parents, if necessary). */)
500 (char_table)
501 Lisp_Object char_table;
502{
503 CHECK_CHAR_TABLE (char_table);
504
505 return XCHAR_TABLE (char_table)->parent;
506}
507
508DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent,
509 2, 2, 0,
510 doc: /* Set the parent char-table of CHAR-TABLE to PARENT.
511PARENT must be either nil or another char-table. */)
512 (char_table, parent)
513 Lisp_Object char_table, parent;
514{
515 Lisp_Object temp;
516
517 CHECK_CHAR_TABLE (char_table);
518
519 if (!NILP (parent))
520 {
521 CHECK_CHAR_TABLE (parent);
522
523 for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent)
524 if (EQ (temp, char_table))
525 error ("Attempt to make a chartable be its own parent");
526 }
527
528 XCHAR_TABLE (char_table)->parent = parent;
529
530 return parent;
531}
532
533DEFUN ("char-table-extra-slot", Fchar_table_extra_slot, Schar_table_extra_slot,
534 2, 2, 0,
535 doc: /* Return the value of CHAR-TABLE's extra-slot number N. */)
536 (char_table, n)
537 Lisp_Object char_table, n;
538{
539 CHECK_CHAR_TABLE (char_table);
540 CHECK_NUMBER (n);
541 if (XINT (n) < 0
542 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
543 args_out_of_range (char_table, n);
544
545 return XCHAR_TABLE (char_table)->extras[XINT (n)];
546}
547
548DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
549 Sset_char_table_extra_slot,
550 3, 3, 0,
551 doc: /* Set CHAR-TABLE's extra-slot number N to VALUE. */)
552 (char_table, n, value)
553 Lisp_Object char_table, n, value;
554{
555 CHECK_CHAR_TABLE (char_table);
556 CHECK_NUMBER (n);
557 if (XINT (n) < 0
558 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
559 args_out_of_range (char_table, n);
560
561 return XCHAR_TABLE (char_table)->extras[XINT (n)] = value;
562}
563\f
564DEFUN ("char-table-range", Fchar_table_range, Schar_table_range,
565 2, 2, 0,
566 doc: /* Return the value in CHAR-TABLE for a range of characters RANGE.
567RANGE should be nil (for the default value),
568a cons of character codes (for characters in the range), or a character code. */)
569 (char_table, range)
570 Lisp_Object char_table, range;
571{
572 Lisp_Object val;
573 CHECK_CHAR_TABLE (char_table);
574
575 if (EQ (range, Qnil))
576 val = XCHAR_TABLE (char_table)->defalt;
577 else if (INTEGERP (range))
578 val = CHAR_TABLE_REF (char_table, XINT (range));
579 else if (CONSP (range))
580 {
581 int from, to;
582
583 CHECK_CHARACTER (XCAR (range));
584 CHECK_CHARACTER (XCDR (range));
585 val = char_table_ref_and_range (char_table, XINT (XCAR (range)),
586 &from, &to);
587 /* Not yet implemented. */
588 }
589 else
590 error ("Invalid RANGE argument to `char-table-range'");
591 return val;
592}
593
594DEFUN ("set-char-table-range", Fset_char_table_range, Sset_char_table_range,
595 3, 3, 0,
596 doc: /*
597Set the value in CHAR-TABLE for characters specified by RANGE to VALUE.
598RANGE should be t (for all characters), nil (for the default value),
599a cons of character codes (for characters in the range), or a character code. */)
600 (char_table, range, value)
601 Lisp_Object char_table, range, value;
602{
603 CHECK_CHAR_TABLE (char_table);
604 if (EQ (range, Qt))
605 {
606 int i;
607
608 XCHAR_TABLE (char_table)->ascii = Qnil;
609 for (i = 0; i < chartab_size[0]; i++)
610 XCHAR_TABLE (char_table)->contents[i] = Qnil;
611 XCHAR_TABLE (char_table)->defalt = value;
612 }
613 else if (EQ (range, Qnil))
614 XCHAR_TABLE (char_table)->defalt = value;
615 else if (INTEGERP (range))
616 char_table_set (char_table, XINT (range), value);
617 else if (CONSP (range))
618 {
619 CHECK_CHARACTER (XCAR (range));
620 CHECK_CHARACTER (XCDR (range));
621 char_table_set_range (char_table,
622 XINT (XCAR (range)), XINT (XCDR (range)), value);
623 }
624 else
625 error ("Invalid RANGE argument to `set-char-table-range'");
626
627 return value;
628}
629
630DEFUN ("set-char-table-default", Fset_char_table_default,
631 Sset_char_table_default, 3, 3, 0,
632 doc: /*
f6e5cae0 633This function is obsolete and has no effect. */)
1ee5d538
KH
634 (char_table, ch, value)
635 Lisp_Object char_table, ch, value;
636{
637 return Qnil;
638}
639
640/* Look up the element in TABLE at index CH, and return it as an
641 integer. If the element is nil, return CH itself. (Actually we do
642 that for any non-integer.) */
643
644int
645char_table_translate (table, ch)
646 Lisp_Object table;
647 int ch;
648{
649 Lisp_Object value;
650 value = Faref (table, make_number (ch));
f6e5cae0 651 if (! INTEGERP (value)) /* fixme: use CHARACTERP? */
1ee5d538
KH
652 return ch;
653 return XINT (value);
654}
655
656static Lisp_Object
657optimize_sub_char_table (table)
658 Lisp_Object table;
659{
660 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
661 int depth = XINT (tbl->depth);
662 Lisp_Object elt, this;
663 int i;
664
665 elt = XSUB_CHAR_TABLE (table)->contents[0];
666 if (SUB_CHAR_TABLE_P (elt))
667 elt = XSUB_CHAR_TABLE (table)->contents[0] = optimize_sub_char_table (elt);
668 if (SUB_CHAR_TABLE_P (elt))
669 return table;
670 for (i = 1; i < chartab_size[depth]; i++)
671 {
672 this = XSUB_CHAR_TABLE (table)->contents[i];
673 if (SUB_CHAR_TABLE_P (this))
674 this = XSUB_CHAR_TABLE (table)->contents[i]
675 = optimize_sub_char_table (this);
676 if (SUB_CHAR_TABLE_P (this)
677 || NILP (Fequal (this, elt)))
678 break;
679 }
680
681 return (i < chartab_size[depth] ? table : elt);
682}
683
684DEFUN ("optimize-char-table", Foptimize_char_table, Soptimize_char_table,
685 1, 1, 0,
686 doc: /* Optimize CHAR-TABLE. */)
687 (char_table)
688 Lisp_Object char_table;
689{
690 Lisp_Object elt;
691 int i;
692
693 CHECK_CHAR_TABLE (char_table);
694
695 for (i = 0; i < chartab_size[0]; i++)
696 {
697 elt = XCHAR_TABLE (char_table)->contents[i];
698 if (SUB_CHAR_TABLE_P (elt))
699 XCHAR_TABLE (char_table)->contents[i] = optimize_sub_char_table (elt);
700 }
701 return Qnil;
702}
703
704\f
705static Lisp_Object
706map_sub_char_table (c_function, function, table, arg, val, range)
707 void (*c_function) P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
708 Lisp_Object function, table, arg, val, range;
709{
710 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
711 int depth = XINT (tbl->depth);
712 int i, c;
713
714 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth];
715 i++, c += chartab_chars[depth])
716 {
717 Lisp_Object this;
718
719 this = tbl->contents[i];
720 if (SUB_CHAR_TABLE_P (this))
721 val = map_sub_char_table (c_function, function, this, arg, val, range);
722 else if (NILP (Fequal (val, this)))
723 {
724 if (! NILP (val))
725 {
726 XCDR (range) = make_number (c - 1);
727 if (depth == 3
728 && EQ (XCAR (range), XCDR (range)))
729 {
730 if (c_function)
731 (*c_function) (arg, XCAR (range), val);
732 else
733 call2 (function, XCAR (range), val);
734 }
735 else
736 {
737 if (c_function)
738 (*c_function) (arg, range, val);
739 else
740 call2 (function, range, val);
741 }
742 }
743 val = this;
744 XCAR (range) = make_number (c);
745 }
746 }
747 return val;
748}
749
750
751/* Map C_FUNCTION or FUNCTION over TABLE, calling it for each
752 character or group of characters that share a value.
753
754 ARG is passed to C_FUNCTION when that is called.
755
756 DEPTH and INDICES are ignored. They are removed in the new
757 feature. */
758
759void
760map_char_table (c_function, function, table, arg, depth, indices)
761 void (*c_function) P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
762 Lisp_Object function, table, arg, *indices;
763 int depth;
764{
765 Lisp_Object range, val;
766 int c, i;
767
768 range = Fcons (make_number (0), Qnil);
769 val = char_table_ref (table, 0);
770
771 for (i = 0, c = 0; i < chartab_size[0]; i++, c += chartab_chars[0])
772 {
773 Lisp_Object this;
774
775 this = XCHAR_TABLE (table)->contents[i];
776 if (SUB_CHAR_TABLE_P (this))
777 val = map_sub_char_table (c_function, function, this, arg, val, range);
778 else if (NILP (Fequal (val, this)))
779 {
780 if (! NILP (val))
781 {
782 XCDR (range) = make_number (c - 1);
783 if (c_function)
784 (*c_function) (arg, range, val);
785 else
786 call2 (function, range, val);
787 }
788 val = this;
789 XCAR (range) = make_number (c);
790 }
791 }
792}
793
794DEFUN ("map-char-table", Fmap_char_table, Smap_char_table,
795 2, 2, 0,
796 doc: /*
f6e5cae0 797Call FUNCTION for each character in CHAR-TABLE.
1ee5d538
KH
798FUNCTION is called with two arguments--a key and a value.
799The key is always a possible IDX argument to `aref'. */)
800 (function, char_table)
801 Lisp_Object function, char_table;
802{
803 CHECK_CHAR_TABLE (char_table);
804
805 map_char_table (NULL, function, char_table, char_table, 0, NULL);
806 return Qnil;
807}
808
e15009d9
KH
809
810static void
811map_sub_char_table_for_charset (c_function, function, table, arg, range,
812 charset, from, to)
813 void (*c_function) P_ ((Lisp_Object, Lisp_Object));
814 Lisp_Object function, table, arg, range;
815 struct charset *charset;
816 unsigned from, to;
817{
818 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
819 int depth = XINT (tbl->depth);
820 int c, i;
821
822 if (depth < 3)
823 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth];
824 i++, c += chartab_chars[depth])
825 {
826 Lisp_Object this;
827
828 this = tbl->contents[i];
829 if (SUB_CHAR_TABLE_P (this))
830 map_sub_char_table_for_charset (c_function, function, this, arg,
831 range, charset, from, to);
832 else
833 {
834 if (! NILP (XCAR (range)))
835 {
836 XSETCDR (range, make_number (c - 1));
837 if (c_function)
838 (*c_function) (arg, range);
839 else
840 call2 (function, range, arg);
841 }
842 XSETCAR (range, Qnil);
843 }
844 }
845 else
846 for (i = 0, c = XINT (tbl->min_char); i < chartab_size[depth]; i++, c ++)
847 {
848 Lisp_Object this;
849 unsigned code;
850
851 this = tbl->contents[i];
852 if (NILP (this)
853 || (charset
854 && (code = ENCODE_CHAR (charset, c),
855 (code < from || code > to))))
856 {
857 if (! NILP (XCAR (range)))
858 {
859 XSETCDR (range, make_number (c - 1));
860 if (c_function)
861 (*c_function) (range, arg);
862 else
863 call2 (function, range, arg);
864 XSETCAR (range, Qnil);
865 }
866 }
867 else
868 {
869 if (NILP (XCAR (range)))
870 XSETCAR (range, make_number (c));
871 }
872 }
873}
874
875
876void
877map_char_table_for_charset (c_function, function, table, arg,
878 charset, from, to)
879 void (*c_function) P_ ((Lisp_Object, Lisp_Object));
880 Lisp_Object function, table, arg;
881 struct charset *charset;
882 unsigned from, to;
883{
884 Lisp_Object range;
885 int c, i;
886
887 if (NILP (char_table_ref (table, 0)))
888 range = Fcons (Qnil, Qnil);
889 else
890 range = Fcons (make_number (0), make_number (0));
891
892 for (i = 0, c = 0; i < chartab_size[0]; i++, c += chartab_chars[0])
893 {
894 Lisp_Object this;
895
896 this = XCHAR_TABLE (table)->contents[i];
897 if (SUB_CHAR_TABLE_P (this))
898 map_sub_char_table_for_charset (c_function, function, this, arg,
899 range, charset, from, to);
900 else
901 {
902 if (! NILP (XCAR (range)))
903 {
904 XSETCDR (range, make_number (c - 1));
905 if (c_function)
906 (*c_function) (arg, range);
907 else
908 call2 (function, range, arg);
909 }
910 XSETCAR (range, Qnil);
911 }
912 }
913 if (! NILP (XCAR (range)))
914 {
915 XSETCDR (range, make_number (c - 1));
916 if (c_function)
917 (*c_function) (arg, range);
918 else
919 call2 (function, range, arg);
920 }
921}
922
923
1ee5d538
KH
924\f
925#if 0
926Lisp_Object
927make_class_table (purpose)
928 Lisp_Object purpose;
929{
930 Lisp_Object table;
931 Lisp_Object args[4];
932
933 args[0] = purpose;
934 args[1] = Qnil;
935 args[2] = QCextra_slots;
936 args[3] = Fmake_vector (make_number (2), Qnil);
937 ASET (args[3], 0, Fmakehash (Qequal));
938 table = Fmake_char_table (4, args);
939 return table;
940}
941
942Lisp_Object
943modify_class_entry (c, val, table, set)
944 int c;
945 Lisp_Object val, table, set;
946{
947 Lisp_Object classes, hash, canon;
948 int i, ival;
949
950 hash = XCHAR_TABLE (table)->extras[0];
951 classes = CHAR_TABLE_REF (table, c);
952
953 if (! BOOL_VECTOR_P (classes))
954 classes = (NILP (set)
955 ? Qnil
956 : Fmake_bool_vector (make_number ((ival / 8) * 8 + 8), Qnil));
957 else if (ival < XBOOL_VECTOR (classes)->size)
958 {
959 Lisp_Object old;
960 old = classes;
961 classes = Fmake_bool_vector (make_number ((ival / 8) * 8 + 8), Qnil);
962 for (i = 0; i < XBOOL_VECTOR (classes)->size; i++)
963 Faset (classes, make_number (i), Faref (old, make_number (i)));
964 Faset (classes, val, set);
965 }
966 else if (NILP (Faref (classes, val)) != NILP (set))
967 {
968 classes = Fcopy_sequence (classes);
969 Faset (classes, val, set);
970 }
971 else
972 classes = Qnil;
973
974 if (!NILP (classes))
975 {
976 canon = Fgethash (classes, hash, Qnil);
977 if (NILP (canon))
978 {
979 canon = classes;
980 Fputhash (canon, canon, hash);
981 }
982 char_table_set (table, c, canon);
983 }
984
985 return val;
986}
987#endif
988
989\f
990void
991syms_of_chartab ()
992{
993 defsubr (&Smake_char_table);
994 defsubr (&Schar_table_parent);
995 defsubr (&Schar_table_subtype);
996 defsubr (&Sset_char_table_parent);
997 defsubr (&Schar_table_extra_slot);
998 defsubr (&Sset_char_table_extra_slot);
999 defsubr (&Schar_table_range);
1000 defsubr (&Sset_char_table_range);
1001 defsubr (&Sset_char_table_default);
1002 defsubr (&Soptimize_char_table);
1003 defsubr (&Smap_char_table);
1004}