aboutsummaryrefslogtreecommitdiffstats
path: root/src/chartab.c
diff options
context:
space:
mode:
authorJoakim Verona2011-07-15 04:39:29 +0200
committerJoakim Verona2011-07-15 04:39:29 +0200
commit4f616a2e7ed1db28da98df90266e9751a8ae9ee1 (patch)
tree74a9dcbe13e945e712ae04a4a94c2202ca720591 /src/chartab.c
parentff2be00005c3aeda6e11d7ed264ce86f02b60958 (diff)
parentec2bc542a4d0127425625e8cb458684bd825675a (diff)
downloademacs-4f616a2e7ed1db28da98df90266e9751a8ae9ee1.tar.gz
emacs-4f616a2e7ed1db28da98df90266e9751a8ae9ee1.zip
merge from upstream
Diffstat (limited to 'src/chartab.c')
-rw-r--r--src/chartab.c583
1 files changed, 506 insertions, 77 deletions
diff --git a/src/chartab.c b/src/chartab.c
index ed5b238646e..efe23eca83f 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -53,7 +53,38 @@ static const int chartab_bits[4] =
53#define CHARTAB_IDX(c, depth, min_char) \ 53#define CHARTAB_IDX(c, depth, min_char) \
54 (((c) - (min_char)) >> chartab_bits[(depth)]) 54 (((c) - (min_char)) >> chartab_bits[(depth)])
55 55
56
57/* Preamble for uniprop (Unicode character property) tables. See the
58 comment of "Unicode character property tables". */
59
60/* Purpose of uniprop tables. */
61static Lisp_Object Qchar_code_property_table;
62
63/* Types of decoder and encoder functions for uniprop values. */
64typedef Lisp_Object (*uniprop_decoder_t) (Lisp_Object, Lisp_Object);
65typedef Lisp_Object (*uniprop_encoder_t) (Lisp_Object, Lisp_Object);
66
67static Lisp_Object uniprop_table_uncompress (Lisp_Object, int);
68static 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)
56 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
57DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0, 88DEFUN ("make-char-table", Fmake_char_table, Smake_char_table, 1, 2, 0,
58 doc: /* Return a newly created char-table, with purpose PURPOSE. 89 doc: /* Return a newly created char-table, with purpose PURPOSE.
59Each element is initialized to INIT, which defaults to nil. 90Each element is initialized to INIT, which defaults to nil.
@@ -107,7 +138,7 @@ make_sub_char_table (int depth, int min_char, Lisp_Object defalt)
107static Lisp_Object 138static Lisp_Object
108char_table_ascii (Lisp_Object table) 139char_table_ascii (Lisp_Object table)
109{ 140{
110 Lisp_Object sub; 141 Lisp_Object sub, val;
111 142
112 sub = XCHAR_TABLE (table)->contents[0]; 143 sub = XCHAR_TABLE (table)->contents[0];
113 if (! SUB_CHAR_TABLE_P (sub)) 144 if (! SUB_CHAR_TABLE_P (sub))
@@ -115,7 +146,10 @@ char_table_ascii (Lisp_Object table)
115 sub = XSUB_CHAR_TABLE (sub)->contents[0]; 146 sub = XSUB_CHAR_TABLE (sub)->contents[0];
116 if (! SUB_CHAR_TABLE_P (sub)) 147 if (! SUB_CHAR_TABLE_P (sub))
117 return sub; 148 return sub;
118 return XSUB_CHAR_TABLE (sub)->contents[0]; 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;
119} 153}
120 154
121static Lisp_Object 155static Lisp_Object
@@ -169,16 +203,19 @@ copy_char_table (Lisp_Object table)
169} 203}
170 204
171static Lisp_Object 205static Lisp_Object
172sub_char_table_ref (Lisp_Object table, int c) 206sub_char_table_ref (Lisp_Object table, int c, int is_uniprop)
173{ 207{
174 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table); 208 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
175 int depth = XINT (tbl->depth); 209 int depth = XINT (tbl->depth);
176 int min_char = XINT (tbl->min_char); 210 int min_char = XINT (tbl->min_char);
177 Lisp_Object val; 211 Lisp_Object val;
212 int idx = CHARTAB_IDX (c, depth, min_char);
178 213
179 val = tbl->contents[CHARTAB_IDX (c, depth, min_char)]; 214 val = tbl->contents[idx];
215 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
216 val = uniprop_table_uncompress (table, idx);
180 if (SUB_CHAR_TABLE_P (val)) 217 if (SUB_CHAR_TABLE_P (val))
181 val = sub_char_table_ref (val, c); 218 val = sub_char_table_ref (val, c, is_uniprop);
182 return val; 219 return val;
183} 220}
184 221
@@ -198,7 +235,7 @@ char_table_ref (Lisp_Object table, int c)
198 { 235 {
199 val = tbl->contents[CHARTAB_IDX (c, 0, 0)]; 236 val = tbl->contents[CHARTAB_IDX (c, 0, 0)];
200 if (SUB_CHAR_TABLE_P (val)) 237 if (SUB_CHAR_TABLE_P (val))
201 val = sub_char_table_ref (val, c); 238 val = sub_char_table_ref (val, c, UNIPROP_TABLE_P (table));
202 } 239 }
203 if (NILP (val)) 240 if (NILP (val))
204 { 241 {
@@ -210,7 +247,8 @@ char_table_ref (Lisp_Object table, int c)
210} 247}
211 248
212static Lisp_Object 249static Lisp_Object
213sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to, Lisp_Object defalt) 250sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to,
251 Lisp_Object defalt, int is_uniprop)
214{ 252{
215 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table); 253 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
216 int depth = XINT (tbl->depth); 254 int depth = XINT (tbl->depth);
@@ -219,8 +257,10 @@ sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to, Lisp
219 Lisp_Object val; 257 Lisp_Object val;
220 258
221 val = tbl->contents[chartab_idx]; 259 val = tbl->contents[chartab_idx];
260 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
261 val = uniprop_table_uncompress (table, chartab_idx);
222 if (SUB_CHAR_TABLE_P (val)) 262 if (SUB_CHAR_TABLE_P (val))
223 val = sub_char_table_ref_and_range (val, c, from, to, defalt); 263 val = sub_char_table_ref_and_range (val, c, from, to, defalt, is_uniprop);
224 else if (NILP (val)) 264 else if (NILP (val))
225 val = defalt; 265 val = defalt;
226 266
@@ -232,8 +272,11 @@ sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to, Lisp
232 c = min_char + idx * chartab_chars[depth] - 1; 272 c = min_char + idx * chartab_chars[depth] - 1;
233 idx--; 273 idx--;
234 this_val = tbl->contents[idx]; 274 this_val = tbl->contents[idx];
275 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
276 this_val = uniprop_table_uncompress (table, idx);
235 if (SUB_CHAR_TABLE_P (this_val)) 277 if (SUB_CHAR_TABLE_P (this_val))
236 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt); 278 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt,
279 is_uniprop);
237 else if (NILP (this_val)) 280 else if (NILP (this_val))
238 this_val = defalt; 281 this_val = defalt;
239 282
@@ -251,8 +294,11 @@ sub_char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to, Lisp
251 294
252 chartab_idx++; 295 chartab_idx++;
253 this_val = tbl->contents[chartab_idx]; 296 this_val = tbl->contents[chartab_idx];
297 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
298 this_val = uniprop_table_uncompress (table, chartab_idx);
254 if (SUB_CHAR_TABLE_P (this_val)) 299 if (SUB_CHAR_TABLE_P (this_val))
255 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt); 300 this_val = sub_char_table_ref_and_range (this_val, c, from, to, defalt,
301 is_uniprop);
256 else if (NILP (this_val)) 302 else if (NILP (this_val))
257 this_val = defalt; 303 this_val = defalt;
258 if (! EQ (this_val, val)) 304 if (! EQ (this_val, val))
@@ -277,17 +323,20 @@ char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
277 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table); 323 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
278 int chartab_idx = CHARTAB_IDX (c, 0, 0), idx; 324 int chartab_idx = CHARTAB_IDX (c, 0, 0), idx;
279 Lisp_Object val; 325 Lisp_Object val;
326 int is_uniprop = UNIPROP_TABLE_P (table);
280 327
281 val = tbl->contents[chartab_idx]; 328 val = tbl->contents[chartab_idx];
282 if (*from < 0) 329 if (*from < 0)
283 *from = 0; 330 *from = 0;
284 if (*to < 0) 331 if (*to < 0)
285 *to = MAX_CHAR; 332 *to = MAX_CHAR;
333 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (val))
334 val = uniprop_table_uncompress (table, chartab_idx);
286 if (SUB_CHAR_TABLE_P (val)) 335 if (SUB_CHAR_TABLE_P (val))
287 val = sub_char_table_ref_and_range (val, c, from, to, tbl->defalt); 336 val = sub_char_table_ref_and_range (val, c, from, to, tbl->defalt,
337 is_uniprop);
288 else if (NILP (val)) 338 else if (NILP (val))
289 val = tbl->defalt; 339 val = tbl->defalt;
290
291 idx = chartab_idx; 340 idx = chartab_idx;
292 while (*from < idx * chartab_chars[0]) 341 while (*from < idx * chartab_chars[0])
293 { 342 {
@@ -296,9 +345,11 @@ char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
296 c = idx * chartab_chars[0] - 1; 345 c = idx * chartab_chars[0] - 1;
297 idx--; 346 idx--;
298 this_val = tbl->contents[idx]; 347 this_val = tbl->contents[idx];
348 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
349 this_val = uniprop_table_uncompress (table, idx);
299 if (SUB_CHAR_TABLE_P (this_val)) 350 if (SUB_CHAR_TABLE_P (this_val))
300 this_val = sub_char_table_ref_and_range (this_val, c, from, to, 351 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
301 tbl->defalt); 352 tbl->defalt, is_uniprop);
302 else if (NILP (this_val)) 353 else if (NILP (this_val))
303 this_val = tbl->defalt; 354 this_val = tbl->defalt;
304 355
@@ -315,9 +366,11 @@ char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
315 chartab_idx++; 366 chartab_idx++;
316 c = chartab_idx * chartab_chars[0]; 367 c = chartab_idx * chartab_chars[0];
317 this_val = tbl->contents[chartab_idx]; 368 this_val = tbl->contents[chartab_idx];
369 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this_val))
370 this_val = uniprop_table_uncompress (table, chartab_idx);
318 if (SUB_CHAR_TABLE_P (this_val)) 371 if (SUB_CHAR_TABLE_P (this_val))
319 this_val = sub_char_table_ref_and_range (this_val, c, from, to, 372 this_val = sub_char_table_ref_and_range (this_val, c, from, to,
320 tbl->defalt); 373 tbl->defalt, is_uniprop);
321 else if (NILP (this_val)) 374 else if (NILP (this_val))
322 this_val = tbl->defalt; 375 this_val = tbl->defalt;
323 if (! EQ (this_val, val)) 376 if (! EQ (this_val, val))
@@ -332,7 +385,7 @@ char_table_ref_and_range (Lisp_Object table, int c, int *from, int *to)
332 385
333 386
334static void 387static void
335sub_char_table_set (Lisp_Object table, int c, Lisp_Object val) 388sub_char_table_set (Lisp_Object table, int c, Lisp_Object val, int is_uniprop)
336{ 389{
337 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table); 390 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
338 int depth = XINT ((tbl)->depth); 391 int depth = XINT ((tbl)->depth);
@@ -347,11 +400,17 @@ sub_char_table_set (Lisp_Object table, int c, Lisp_Object val)
347 sub = tbl->contents[i]; 400 sub = tbl->contents[i];
348 if (! SUB_CHAR_TABLE_P (sub)) 401 if (! SUB_CHAR_TABLE_P (sub))
349 { 402 {
350 sub = make_sub_char_table (depth + 1, 403 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (sub))
351 min_char + i * chartab_chars[depth], sub); 404 sub = uniprop_table_uncompress (table, i);
352 tbl->contents[i] = sub; 405 else
406 {
407 sub = make_sub_char_table (depth + 1,
408 min_char + i * chartab_chars[depth],
409 sub);
410 tbl->contents[i] = sub;
411 }
353 } 412 }
354 sub_char_table_set (sub, c, val); 413 sub_char_table_set (sub, c, val, is_uniprop);
355 } 414 }
356} 415}
357 416
@@ -376,7 +435,7 @@ char_table_set (Lisp_Object table, int c, Lisp_Object val)
376 sub = make_sub_char_table (1, i * chartab_chars[0], sub); 435 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
377 tbl->contents[i] = sub; 436 tbl->contents[i] = sub;
378 } 437 }
379 sub_char_table_set (sub, c, val); 438 sub_char_table_set (sub, c, val, UNIPROP_TABLE_P (table));
380 if (ASCII_CHAR_P (c)) 439 if (ASCII_CHAR_P (c))
381 tbl->ascii = char_table_ascii (table); 440 tbl->ascii = char_table_ascii (table);
382 } 441 }
@@ -384,30 +443,40 @@ char_table_set (Lisp_Object table, int c, Lisp_Object val)
384} 443}
385 444
386static void 445static void
387sub_char_table_set_range (Lisp_Object *table, int depth, int min_char, int from, int to, Lisp_Object val) 446sub_char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val,
447 int is_uniprop)
388{ 448{
389 int max_char = min_char + chartab_chars[depth] - 1; 449 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
390 450 int depth = XINT ((tbl)->depth);
391 if (depth == 3 || (from <= min_char && to >= max_char)) 451 int min_char = XINT ((tbl)->min_char);
392 *table = val; 452 int chars_in_block = chartab_chars[depth];
393 else 453 int i, c, lim = chartab_size[depth];
454
455 if (from < min_char)
456 from = min_char;
457 i = CHARTAB_IDX (from, depth, min_char);
458 c = min_char + chars_in_block * i;
459 for (; i < lim; i++, c += chars_in_block)
394 { 460 {
395 int i; 461 if (c > to)
396 unsigned j; 462 break;
397 463 if (from <= c && c + chars_in_block - 1 <= to)
398 depth++; 464 tbl->contents[i] = val;
399 if (! SUB_CHAR_TABLE_P (*table)) 465 else
400 *table = make_sub_char_table (depth, min_char, *table); 466 {
401 if (from < min_char) 467 Lisp_Object sub = tbl->contents[i];
402 from = min_char; 468 if (! SUB_CHAR_TABLE_P (sub))
403 if (to > max_char) 469 {
404 to = max_char; 470 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (sub))
405 i = CHARTAB_IDX (from, depth, min_char); 471 sub = uniprop_table_uncompress (table, i);
406 j = CHARTAB_IDX (to, depth, min_char); 472 else
407 min_char += chartab_chars[depth] * i; 473 {
408 for (j++; i < j; i++, min_char += chartab_chars[depth]) 474 sub = make_sub_char_table (depth + 1, c, sub);
409 sub_char_table_set_range (XSUB_CHAR_TABLE (*table)->contents + i, 475 tbl->contents[i] = sub;
410 depth, min_char, from, to, val); 476 }
477 }
478 sub_char_table_set_range (sub, from, to, val, is_uniprop);
479 }
411 } 480 }
412} 481}
413 482
@@ -416,17 +485,33 @@ Lisp_Object
416char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val) 485char_table_set_range (Lisp_Object table, int from, int to, Lisp_Object val)
417{ 486{
418 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table); 487 struct Lisp_Char_Table *tbl = XCHAR_TABLE (table);
419 Lisp_Object *contents = tbl->contents;
420 int i;
421 488
422 if (from == to) 489 if (from == to)
423 char_table_set (table, from, val); 490 char_table_set (table, from, val);
424 else 491 else
425 { 492 {
426 unsigned lim = to / chartab_chars[0] + 1; 493 int is_uniprop = UNIPROP_TABLE_P (table);
427 for (i = CHARTAB_IDX (from, 0, 0); i < lim; i++) 494 int lim = CHARTAB_IDX (to, 0, 0);
428 sub_char_table_set_range (contents + i, 0, i * chartab_chars[0], 495 int i, c;
429 from, to, val); 496
497 for (i = CHARTAB_IDX (from, 0, 0), c = 0; i <= lim;
498 i++, c += chartab_chars[0])
499 {
500 if (c > to)
501 break;
502 if (from <= c && c + chartab_chars[0] - 1 <= to)
503 tbl->contents[i] = val;
504 else
505 {
506 Lisp_Object sub = tbl->contents[i];
507 if (! SUB_CHAR_TABLE_P (sub))
508 {
509 sub = make_sub_char_table (1, i * chartab_chars[0], sub);
510 tbl->contents[i] = sub;
511 }
512 sub_char_table_set_range (sub, from, to, val, is_uniprop);
513 }
514 }
430 if (ASCII_CHAR_P (from)) 515 if (ASCII_CHAR_P (from))
431 tbl->ascii = char_table_ascii (table); 516 tbl->ascii = char_table_ascii (table);
432 } 517 }
@@ -504,6 +589,8 @@ DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot,
504 (Lisp_Object char_table, Lisp_Object n, Lisp_Object value) 589 (Lisp_Object char_table, Lisp_Object n, Lisp_Object value)
505{ 590{
506 CHECK_CHAR_TABLE (char_table); 591 CHECK_CHAR_TABLE (char_table);
592 if (EQ (XCHAR_TABLE (char_table)->purpose, Qchar_code_property_table))
593 error ("Can't change extra-slot of char-code-property-table");
507 CHECK_NUMBER (n); 594 CHECK_NUMBER (n);
508 if (XINT (n) < 0 595 if (XINT (n) < 0
509 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table))) 596 || XINT (n) >= CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (char_table)))
@@ -532,8 +619,9 @@ a cons of character codes (for characters in the range), or a character code. *
532 619
533 CHECK_CHARACTER_CAR (range); 620 CHECK_CHARACTER_CAR (range);
534 CHECK_CHARACTER_CDR (range); 621 CHECK_CHARACTER_CDR (range);
535 val = char_table_ref_and_range (char_table, XFASTINT (XCAR (range)), 622 from = XFASTINT (XCAR (range));
536 &from, &to); 623 to = XFASTINT (XCDR (range));
624 val = char_table_ref_and_range (char_table, from, &from, &to);
537 /* Not yet implemented. */ 625 /* Not yet implemented. */
538 } 626 }
539 else 627 else
@@ -655,8 +743,7 @@ equivalent and can be merged. It defaults to `equal'. */)
655/* Map C_FUNCTION or FUNCTION over TABLE (top or sub char-table), 743/* Map C_FUNCTION or FUNCTION over TABLE (top or sub char-table),
656 calling it for each character or group of characters that share a 744 calling it for each character or group of characters that share a
657 value. RANGE is a cons (FROM . TO) specifying the range of target 745 value. RANGE is a cons (FROM . TO) specifying the range of target
658 characters, VAL is a value of FROM in TABLE, DEFAULT_VAL is the 746 characters, VAL is a value of FROM in TABLE, TOP is the top
659 default value of the char-table, PARENT is the parent of the
660 char-table. 747 char-table.
661 748
662 ARG is passed to C_FUNCTION when that is called. 749 ARG is passed to C_FUNCTION when that is called.
@@ -669,10 +756,8 @@ equivalent and can be merged. It defaults to `equal'. */)
669static Lisp_Object 756static Lisp_Object
670map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object), 757map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
671 Lisp_Object function, Lisp_Object table, Lisp_Object arg, Lisp_Object val, 758 Lisp_Object function, Lisp_Object table, Lisp_Object arg, Lisp_Object val,
672 Lisp_Object range, Lisp_Object default_val, Lisp_Object parent) 759 Lisp_Object range, Lisp_Object top)
673{ 760{
674 /* Pointer to the elements of TABLE. */
675 Lisp_Object *contents;
676 /* Depth of TABLE. */ 761 /* Depth of TABLE. */
677 int depth; 762 int depth;
678 /* Minimum and maxinum characters covered by TABLE. */ 763 /* Minimum and maxinum characters covered by TABLE. */
@@ -681,20 +766,20 @@ map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
681 int chars_in_block; 766 int chars_in_block;
682 int from = XINT (XCAR (range)), to = XINT (XCDR (range)); 767 int from = XINT (XCAR (range)), to = XINT (XCDR (range));
683 int i, c; 768 int i, c;
769 int is_uniprop = UNIPROP_TABLE_P (top);
770 uniprop_decoder_t decoder = UNIPROP_GET_DECODER (top);
684 771
685 if (SUB_CHAR_TABLE_P (table)) 772 if (SUB_CHAR_TABLE_P (table))
686 { 773 {
687 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table); 774 struct Lisp_Sub_Char_Table *tbl = XSUB_CHAR_TABLE (table);
688 775
689 depth = XINT (tbl->depth); 776 depth = XINT (tbl->depth);
690 contents = tbl->contents;
691 min_char = XINT (tbl->min_char); 777 min_char = XINT (tbl->min_char);
692 max_char = min_char + chartab_chars[depth - 1] - 1; 778 max_char = min_char + chartab_chars[depth - 1] - 1;
693 } 779 }
694 else 780 else
695 { 781 {
696 depth = 0; 782 depth = 0;
697 contents = XCHAR_TABLE (table)->contents;
698 min_char = 0; 783 min_char = 0;
699 max_char = MAX_CHAR; 784 max_char = MAX_CHAR;
700 } 785 }
@@ -710,28 +795,33 @@ map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
710 for (c = min_char + chars_in_block * i; c <= max_char; 795 for (c = min_char + chars_in_block * i; c <= max_char;
711 i++, c += chars_in_block) 796 i++, c += chars_in_block)
712 { 797 {
713 Lisp_Object this = contents[i]; 798 Lisp_Object this = (SUB_CHAR_TABLE_P (table)
799 ? XSUB_CHAR_TABLE (table)->contents[i]
800 : XCHAR_TABLE (table)->contents[i]);
714 int nextc = c + chars_in_block; 801 int nextc = c + chars_in_block;
715 802
803 if (is_uniprop && UNIPROP_COMPRESSED_FORM_P (this))
804 this = uniprop_table_uncompress (table, i);
716 if (SUB_CHAR_TABLE_P (this)) 805 if (SUB_CHAR_TABLE_P (this))
717 { 806 {
718 if (to >= nextc) 807 if (to >= nextc)
719 XSETCDR (range, make_number (nextc - 1)); 808 XSETCDR (range, make_number (nextc - 1));
720 val = map_sub_char_table (c_function, function, this, arg, 809 val = map_sub_char_table (c_function, function, this, arg,
721 val, range, default_val, parent); 810 val, range, top);
722 } 811 }
723 else 812 else
724 { 813 {
725 if (NILP (this)) 814 if (NILP (this))
726 this = default_val; 815 this = XCHAR_TABLE (top)->defalt;
727 if (!EQ (val, this)) 816 if (!EQ (val, this))
728 { 817 {
729 int different_value = 1; 818 int different_value = 1;
730 819
731 if (NILP (val)) 820 if (NILP (val))
732 { 821 {
733 if (! NILP (parent)) 822 if (! NILP (XCHAR_TABLE (top)->parent))
734 { 823 {
824 Lisp_Object parent = XCHAR_TABLE (top)->parent;
735 Lisp_Object temp = XCHAR_TABLE (parent)->parent; 825 Lisp_Object temp = XCHAR_TABLE (parent)->parent;
736 826
737 /* This is to get a value of FROM in PARENT 827 /* This is to get a value of FROM in PARENT
@@ -742,8 +832,7 @@ map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
742 XSETCDR (range, make_number (c - 1)); 832 XSETCDR (range, make_number (c - 1));
743 val = map_sub_char_table (c_function, function, 833 val = map_sub_char_table (c_function, function,
744 parent, arg, val, range, 834 parent, arg, val, range,
745 XCHAR_TABLE (parent)->defalt, 835 parent);
746 XCHAR_TABLE (parent)->parent);
747 if (EQ (val, this)) 836 if (EQ (val, this))
748 different_value = 0; 837 different_value = 0;
749 } 838 }
@@ -756,14 +845,22 @@ map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
756 if (c_function) 845 if (c_function)
757 (*c_function) (arg, XCAR (range), val); 846 (*c_function) (arg, XCAR (range), val);
758 else 847 else
759 call2 (function, XCAR (range), val); 848 {
849 if (decoder)
850 val = decoder (top, val);
851 call2 (function, XCAR (range), val);
852 }
760 } 853 }
761 else 854 else
762 { 855 {
763 if (c_function) 856 if (c_function)
764 (*c_function) (arg, range, val); 857 (*c_function) (arg, range, val);
765 else 858 else
766 call2 (function, range, val); 859 {
860 if (decoder)
861 val = decoder (top, val);
862 call2 (function, range, val);
863 }
767 } 864 }
768 } 865 }
769 val = this; 866 val = this;
@@ -783,35 +880,39 @@ map_sub_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
783 ARG is passed to C_FUNCTION when that is called. */ 880 ARG is passed to C_FUNCTION when that is called. */
784 881
785void 882void
786map_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object), Lisp_Object function, Lisp_Object table, Lisp_Object arg) 883map_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object),
884 Lisp_Object function, Lisp_Object table, Lisp_Object arg)
787{ 885{
788 Lisp_Object range, val; 886 Lisp_Object range, val, parent;
789 struct gcpro gcpro1, gcpro2, gcpro3; 887 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
888 uniprop_decoder_t decoder = UNIPROP_GET_DECODER (table);
790 889
791 range = Fcons (make_number (0), make_number (MAX_CHAR)); 890 range = Fcons (make_number (0), make_number (MAX_CHAR));
792 GCPRO3 (table, arg, range); 891 parent = XCHAR_TABLE (table)->parent;
892
893 GCPRO4 (table, arg, range, parent);
793 val = XCHAR_TABLE (table)->ascii; 894 val = XCHAR_TABLE (table)->ascii;
794 if (SUB_CHAR_TABLE_P (val)) 895 if (SUB_CHAR_TABLE_P (val))
795 val = XSUB_CHAR_TABLE (val)->contents[0]; 896 val = XSUB_CHAR_TABLE (val)->contents[0];
796 val = map_sub_char_table (c_function, function, table, arg, val, range, 897 val = map_sub_char_table (c_function, function, table, arg, val, range,
797 XCHAR_TABLE (table)->defalt, 898 table);
798 XCHAR_TABLE (table)->parent); 899
799 /* If VAL is nil and TABLE has a parent, we must consult the parent 900 /* If VAL is nil and TABLE has a parent, we must consult the parent
800 recursively. */ 901 recursively. */
801 while (NILP (val) && ! NILP (XCHAR_TABLE (table)->parent)) 902 while (NILP (val) && ! NILP (XCHAR_TABLE (table)->parent))
802 { 903 {
803 Lisp_Object parent = XCHAR_TABLE (table)->parent; 904 Lisp_Object temp;
804 Lisp_Object temp = XCHAR_TABLE (parent)->parent;
805 int from = XINT (XCAR (range)); 905 int from = XINT (XCAR (range));
806 906
907 parent = XCHAR_TABLE (table)->parent;
908 temp = XCHAR_TABLE (parent)->parent;
807 /* This is to get a value of FROM in PARENT without checking the 909 /* This is to get a value of FROM in PARENT without checking the
808 parent of PARENT. */ 910 parent of PARENT. */
809 XCHAR_TABLE (parent)->parent = Qnil; 911 XCHAR_TABLE (parent)->parent = Qnil;
810 val = CHAR_TABLE_REF (parent, from); 912 val = CHAR_TABLE_REF (parent, from);
811 XCHAR_TABLE (parent)->parent = temp; 913 XCHAR_TABLE (parent)->parent = temp;
812 val = map_sub_char_table (c_function, function, parent, arg, val, range, 914 val = map_sub_char_table (c_function, function, parent, arg, val, range,
813 XCHAR_TABLE (parent)->defalt, 915 parent);
814 XCHAR_TABLE (parent)->parent);
815 table = parent; 916 table = parent;
816 } 917 }
817 918
@@ -822,14 +923,22 @@ map_char_table (void (*c_function) (Lisp_Object, Lisp_Object, Lisp_Object), Lisp
822 if (c_function) 923 if (c_function)
823 (*c_function) (arg, XCAR (range), val); 924 (*c_function) (arg, XCAR (range), val);
824 else 925 else
825 call2 (function, XCAR (range), val); 926 {
927 if (decoder)
928 val = decoder (table, val);
929 call2 (function, XCAR (range), val);
930 }
826 } 931 }
827 else 932 else
828 { 933 {
829 if (c_function) 934 if (c_function)
830 (*c_function) (arg, range, val); 935 (*c_function) (arg, range, val);
831 else 936 else
832 call2 (function, range, val); 937 {
938 if (decoder)
939 val = decoder (table, val);
940 call2 (function, range, val);
941 }
833 } 942 }
834 } 943 }
835 944
@@ -984,9 +1093,314 @@ map_char_table_for_charset (void (*c_function) (Lisp_Object, Lisp_Object),
984} 1093}
985 1094
986 1095
1096/* Unicode character property tables.
1097
1098 This section provides a convenient and efficient way to get a
1099 Unicode character property from C code (from Lisp, you must use
1100 get-char-code-property).
1101
1102 The typical usage is to get a char-table for a specific property at
1103 a proper initialization time as this:
1104
1105 Lisp_Object bidi_class_table = uniprop_table (intern ("bidi-class"));
1106
1107 and get a property value for character CH as this:
1108
1109 Lisp_Object bidi_class = CHAR_TABLE_REF (CH, bidi_class_table);
1110
1111 In this case, what you actually get is an index number to the
1112 vector of property values (symbols nil, L, R, etc).
1113
1114 A table for Unicode character property has these characteristics:
1115
1116 o The purpose is `char-code-property-table', which implies that the
1117 table has 5 extra slots.
1118
1119 o The second extra slot is a Lisp function, an index (integer) to
1120 the array uniprop_decoder[], or nil. If it is a Lisp function, we
1121 can't use such a table from C (at the moment). If it is nil, it
1122 means that we don't have to decode values.
1123
1124 o The third extra slot is a Lisp function, an index (integer) to
1125 the array uniprop_enncoder[], or nil. If it is a Lisp function, we
1126 can't use such a table from C (at the moment). If it is nil, it
1127 means that we don't have to encode values. */
1128
1129
1130/* Uncompress the IDXth element of sub-char-table TABLE. */
1131
1132static Lisp_Object
1133uniprop_table_uncompress (Lisp_Object table, int idx)
1134{
1135 Lisp_Object val = XSUB_CHAR_TABLE (table)->contents[idx];
1136 int min_char = (XINT (XSUB_CHAR_TABLE (table)->min_char)
1137 + chartab_chars[2] * idx);
1138 Lisp_Object sub = make_sub_char_table (3, min_char, Qnil);
1139 struct Lisp_Sub_Char_Table *subtbl = XSUB_CHAR_TABLE (sub);
1140 const unsigned char *p, *pend;
1141
1142 XSUB_CHAR_TABLE (table)->contents[idx] = sub;
1143 p = SDATA (val), pend = p + SBYTES (val);
1144 if (*p == 1)
1145 {
1146 /* SIMPLE TABLE */
1147 p++;
1148 idx = STRING_CHAR_ADVANCE (p);
1149 while (p < pend && idx < chartab_chars[2])
1150 {
1151 int v = STRING_CHAR_ADVANCE (p);
1152 subtbl->contents[idx++] = v > 0 ? make_number (v) : Qnil;
1153 }
1154 }
1155 else if (*p == 2)
1156 {
1157 /* RUN-LENGTH TABLE */
1158 p++;
1159 for (idx = 0; p < pend; )
1160 {
1161 int v = STRING_CHAR_ADVANCE (p);
1162 int count = 1;
1163 int len;
1164
1165 if (p < pend)
1166 {
1167 count = STRING_CHAR_AND_LENGTH (p, len);
1168 if (count < 128)
1169 count = 1;
1170 else
1171 {
1172 count -= 128;
1173 p += len;
1174 }
1175 }
1176 while (count-- > 0)
1177 subtbl->contents[idx++] = make_number (v);
1178 }
1179 }
1180/* It seems that we don't need this function because C code won't need
1181 to get a property that is compressed in this form. */
1182#if 0
1183 else if (*p == 0)
1184 {
1185 /* WORD-LIST TABLE */
1186 }
1187#endif
1188 return sub;
1189}
1190
1191
1192/* Decode VALUE as an elemnet of char-table TABLE. */
1193
1194static Lisp_Object
1195uniprop_decode_value_run_length (Lisp_Object table, Lisp_Object value)
1196{
1197 if (VECTORP (XCHAR_TABLE (table)->extras[4]))
1198 {
1199 Lisp_Object valvec = XCHAR_TABLE (table)->extras[4];
1200
1201 if (XINT (value) >= 0 && XINT (value) < ASIZE (valvec))
1202 value = AREF (valvec, XINT (value));
1203 }
1204 return value;
1205}
1206
1207static uniprop_decoder_t uniprop_decoder [] =
1208 { uniprop_decode_value_run_length };
1209
1210static int uniprop_decoder_count
1211 = (sizeof uniprop_decoder) / sizeof (uniprop_decoder[0]);
1212
1213
1214/* Return the decoder of char-table TABLE or nil if none. */
1215
1216static uniprop_decoder_t
1217uniprop_get_decoder (Lisp_Object table)
1218{
1219 int i;
1220
1221 if (! INTEGERP (XCHAR_TABLE (table)->extras[1]))
1222 return NULL;
1223 i = XINT (XCHAR_TABLE (table)->extras[1]);
1224 if (i < 0 || i >= uniprop_decoder_count)
1225 return NULL;
1226 return uniprop_decoder[i];
1227}
1228
1229
1230/* Encode VALUE as an element of char-table TABLE which contains
1231 characters as elements. */
1232
1233static Lisp_Object
1234uniprop_encode_value_character (Lisp_Object table, Lisp_Object value)
1235{
1236 if (! NILP (value) && ! CHARACTERP (value))
1237 wrong_type_argument (Qintegerp, value);
1238 return value;
1239}
1240
1241
1242/* Encode VALUE as an element of char-table TABLE which adopts RUN-LENGTH
1243 compression. */
1244
1245static Lisp_Object
1246uniprop_encode_value_run_length (Lisp_Object table, Lisp_Object value)
1247{
1248 Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
1249 int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
1250
1251 for (i = 0; i < size; i++)
1252 if (EQ (value, value_table[i]))
1253 break;
1254 if (i == size)
1255 wrong_type_argument (build_string ("Unicode property value"), value);
1256 return make_number (i);
1257}
1258
1259
1260/* Encode VALUE as an element of char-table TABLE which adopts RUN-LENGTH
1261 compression and contains numbers as elements . */
1262
1263static Lisp_Object
1264uniprop_encode_value_numeric (Lisp_Object table, Lisp_Object value)
1265{
1266 Lisp_Object *value_table = XVECTOR (XCHAR_TABLE (table)->extras[4])->contents;
1267 int i, size = ASIZE (XCHAR_TABLE (table)->extras[4]);
1268
1269 CHECK_NUMBER (value);
1270 for (i = 0; i < size; i++)
1271 if (EQ (value, value_table[i]))
1272 break;
1273 value = make_number (i);
1274 if (i == size)
1275 {
1276 Lisp_Object args[2];
1277
1278 args[0] = XCHAR_TABLE (table)->extras[4];
1279 args[1] = Fmake_vector (make_number (1), value);
1280 XCHAR_TABLE (table)->extras[4] = Fvconcat (2, args);
1281 }
1282 return make_number (i);
1283}
1284
1285static uniprop_encoder_t uniprop_encoder[] =
1286 { uniprop_encode_value_character,
1287 uniprop_encode_value_run_length,
1288 uniprop_encode_value_numeric };
1289
1290static int uniprop_encoder_count
1291 = (sizeof uniprop_encoder) / sizeof (uniprop_encoder[0]);
1292
1293
1294/* Return the encoder of char-table TABLE or nil if none. */
1295
1296static uniprop_decoder_t
1297uniprop_get_encoder (Lisp_Object table)
1298{
1299 int i;
1300
1301 if (! INTEGERP (XCHAR_TABLE (table)->extras[2]))
1302 return NULL;
1303 i = XINT (XCHAR_TABLE (table)->extras[2]);
1304 if (i < 0 || i >= uniprop_encoder_count)
1305 return NULL;
1306 return uniprop_encoder[i];
1307}
1308
1309/* Return a char-table for Unicode character property PROP. This
1310 function may load a Lisp file and thus may cause
1311 garbage-collection. */
1312
1313static Lisp_Object
1314uniprop_table (Lisp_Object prop)
1315{
1316 Lisp_Object val, table, result;
1317
1318 val = Fassq (prop, Vchar_code_property_alist);
1319 if (! CONSP (val))
1320 return Qnil;
1321 table = XCDR (val);
1322 if (STRINGP (table))
1323 {
1324 struct gcpro gcpro1;
1325 GCPRO1 (val);
1326 result = Fload (concat2 (build_string ("international/"), table),
1327 Qt, Qt, Qt, Qt);
1328 UNGCPRO;
1329 if (NILP (result))
1330 return Qnil;
1331 table = XCDR (val);
1332 }
1333 if (! CHAR_TABLE_P (table)
1334 || ! UNIPROP_TABLE_P (table))
1335 return Qnil;
1336 val = XCHAR_TABLE (table)->extras[1];
1337 if (INTEGERP (val)
1338 ? (XINT (val) < 0 || XINT (val) >= uniprop_decoder_count)
1339 : ! NILP (val))
1340 return Qnil;
1341 /* Prepare ASCII values in advance for CHAR_TABLE_REF. */
1342 XCHAR_TABLE (table)->ascii = char_table_ascii (table);
1343 return table;
1344}
1345
1346DEFUN ("unicode-property-table-internal", Funicode_property_table_internal,
1347 Sunicode_property_table_internal, 1, 1, 0,
1348 doc: /* Return a char-table for Unicode character property PROP.
1349Use `get-unicode-property-internal' and
1350`put-unicode-property-internal' instead of `aref' and `aset' to get
1351and put an element value. */)
1352 (Lisp_Object prop)
1353{
1354 Lisp_Object table = uniprop_table (prop);
1355
1356 if (CHAR_TABLE_P (table))
1357 return table;
1358 return Fcdr (Fassq (prop, Vchar_code_property_alist));
1359}
1360
1361DEFUN ("get-unicode-property-internal", Fget_unicode_property_internal,
1362 Sget_unicode_property_internal, 2, 2, 0,
1363 doc: /* Return an element of CHAR-TABLE for character CH.
1364CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1365 (Lisp_Object char_table, Lisp_Object ch)
1366{
1367 Lisp_Object val;
1368 uniprop_decoder_t decoder;
1369
1370 CHECK_CHAR_TABLE (char_table);
1371 CHECK_CHARACTER (ch);
1372 if (! UNIPROP_TABLE_P (char_table))
1373 error ("Invalid Unicode property table");
1374 val = CHAR_TABLE_REF (char_table, XINT (ch));
1375 decoder = uniprop_get_decoder (char_table);
1376 return (decoder ? decoder (char_table, val) : val);
1377}
1378
1379DEFUN ("put-unicode-property-internal", Fput_unicode_property_internal,
1380 Sput_unicode_property_internal, 3, 3, 0,
1381 doc: /* Set an element of CHAR-TABLE for character CH to VALUE.
1382CHAR-TABLE must be what returned by `unicode-property-table-internal'. */)
1383 (Lisp_Object char_table, Lisp_Object ch, Lisp_Object value)
1384{
1385 uniprop_encoder_t encoder;
1386
1387 CHECK_CHAR_TABLE (char_table);
1388 CHECK_CHARACTER (ch);
1389 if (! UNIPROP_TABLE_P (char_table))
1390 error ("Invalid Unicode property table");
1391 encoder = uniprop_get_encoder (char_table);
1392 if (encoder)
1393 value = encoder (char_table, value);
1394 CHAR_TABLE_SET (char_table, XINT (ch), value);
1395 return Qnil;
1396}
1397
1398
987void 1399void
988syms_of_chartab (void) 1400syms_of_chartab (void)
989{ 1401{
1402 DEFSYM (Qchar_code_property_table, "char-code-property-table");
1403
990 defsubr (&Smake_char_table); 1404 defsubr (&Smake_char_table);
991 defsubr (&Schar_table_parent); 1405 defsubr (&Schar_table_parent);
992 defsubr (&Schar_table_subtype); 1406 defsubr (&Schar_table_subtype);
@@ -998,4 +1412,19 @@ syms_of_chartab (void)
998 defsubr (&Sset_char_table_default); 1412 defsubr (&Sset_char_table_default);
999 defsubr (&Soptimize_char_table); 1413 defsubr (&Soptimize_char_table);
1000 defsubr (&Smap_char_table); 1414 defsubr (&Smap_char_table);
1415 defsubr (&Sunicode_property_table_internal);
1416 defsubr (&Sget_unicode_property_internal);
1417 defsubr (&Sput_unicode_property_internal);
1418
1419 /* Each element has the form (PROP . TABLE).
1420 PROP is a symbol representing a character property.
1421 TABLE is a char-table containing the property value for each character.
1422 TABLE may be a name of file to load to build a char-table.
1423 This variable should be modified only through
1424 `define-char-code-property'. */
1425
1426 DEFVAR_LISP ("char-code-property-alist", Vchar_code_property_alist,
1427 doc: /* Alist of character property name vs char-table containing property values.
1428Internal use only. */);
1429 Vchar_code_property_alist = Qnil;
1001} 1430}