diff options
| author | Paul Eggert | 2019-01-13 15:45:14 -0800 |
|---|---|---|
| committer | Paul Eggert | 2019-01-13 15:46:44 -0800 |
| commit | 1a722e888454a0cb24dffc35455467688b4b4c60 (patch) | |
| tree | 715e89cb287001ec3857aacbe988bf5ec0d9f6fd /src | |
| parent | 800d3815e4a82f83b98cf87b205dcfdb0670907f (diff) | |
| download | emacs-1a722e888454a0cb24dffc35455467688b4b4c60.tar.gz emacs-1a722e888454a0cb24dffc35455467688b4b4c60.zip | |
Fix translation-region bug with MAX_CHAR
Also, clean up the code a bit.
Actually I discovered the bug while cleaning up the code.
* src/editfns.c (Fsubst_char_in_region)
(Ftranslate_region_internal): Use bool for booleans.
(Ftranslate_region_internal): Fix off-by-1 bug when a
translation table translates the maximum char. Assume C99
decl-after-statement, similar minor cleanups.
* test/src/editfns-tests.el (test-translate-region-internal):
New test.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 82 |
1 files changed, 35 insertions, 47 deletions
diff --git a/src/editfns.c b/src/editfns.c index c6ad4c0547e..55127011d82 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -2322,7 +2322,7 @@ Both characters must have the same length of multi-byte form. */) | |||
| 2322 | /* replace_range is less efficient, because it moves the gap, | 2322 | /* replace_range is less efficient, because it moves the gap, |
| 2323 | but it handles combining correctly. */ | 2323 | but it handles combining correctly. */ |
| 2324 | replace_range (pos, pos + 1, string, | 2324 | replace_range (pos, pos + 1, string, |
| 2325 | 0, 0, 1, 0); | 2325 | false, false, true, false); |
| 2326 | pos_byte_next = CHAR_TO_BYTE (pos); | 2326 | pos_byte_next = CHAR_TO_BYTE (pos); |
| 2327 | if (pos_byte_next > pos_byte) | 2327 | if (pos_byte_next > pos_byte) |
| 2328 | /* Before combining happened. We should not increment | 2328 | /* Before combining happened. We should not increment |
| @@ -2433,60 +2433,53 @@ From START to END, translate characters according to TABLE. | |||
| 2433 | TABLE is a string or a char-table; the Nth character in it is the | 2433 | TABLE is a string or a char-table; the Nth character in it is the |
| 2434 | mapping for the character with code N. | 2434 | mapping for the character with code N. |
| 2435 | It returns the number of characters changed. */) | 2435 | It returns the number of characters changed. */) |
| 2436 | (Lisp_Object start, Lisp_Object end, register Lisp_Object table) | 2436 | (Lisp_Object start, Lisp_Object end, Lisp_Object table) |
| 2437 | { | 2437 | { |
| 2438 | register unsigned char *tt; /* Trans table. */ | 2438 | int translatable_chars = MAX_CHAR + 1; |
| 2439 | register int nc; /* New character. */ | ||
| 2440 | ptrdiff_t cnt; /* Number of changes made. */ | ||
| 2441 | ptrdiff_t size; /* Size of translate table. */ | ||
| 2442 | ptrdiff_t pos, pos_byte, end_pos; | ||
| 2443 | bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters)); | 2439 | bool multibyte = !NILP (BVAR (current_buffer, enable_multibyte_characters)); |
| 2444 | bool string_multibyte UNINIT; | 2440 | bool string_multibyte UNINIT; |
| 2445 | 2441 | ||
| 2446 | validate_region (&start, &end); | 2442 | validate_region (&start, &end); |
| 2447 | if (CHAR_TABLE_P (table)) | 2443 | if (STRINGP (table)) |
| 2448 | { | 2444 | { |
| 2449 | if (! EQ (XCHAR_TABLE (table)->purpose, Qtranslation_table)) | 2445 | if (! multibyte) |
| 2450 | error ("Not a translation table"); | ||
| 2451 | size = MAX_CHAR; | ||
| 2452 | tt = NULL; | ||
| 2453 | } | ||
| 2454 | else | ||
| 2455 | { | ||
| 2456 | CHECK_STRING (table); | ||
| 2457 | |||
| 2458 | if (! multibyte && (SCHARS (table) < SBYTES (table))) | ||
| 2459 | table = string_make_unibyte (table); | 2446 | table = string_make_unibyte (table); |
| 2460 | string_multibyte = SCHARS (table) < SBYTES (table); | 2447 | translatable_chars = min (translatable_chars, SBYTES (table)); |
| 2461 | size = SBYTES (table); | 2448 | string_multibyte = STRING_MULTIBYTE (table); |
| 2462 | tt = SDATA (table); | ||
| 2463 | } | 2449 | } |
| 2450 | else if (! (CHAR_TABLE_P (table) | ||
| 2451 | && EQ (XCHAR_TABLE (table)->purpose, Qtranslation_table))) | ||
| 2452 | error ("Not a translation table"); | ||
| 2464 | 2453 | ||
| 2465 | pos = XFIXNUM (start); | 2454 | ptrdiff_t pos = XFIXNUM (start); |
| 2466 | pos_byte = CHAR_TO_BYTE (pos); | 2455 | ptrdiff_t pos_byte = CHAR_TO_BYTE (pos); |
| 2467 | end_pos = XFIXNUM (end); | 2456 | ptrdiff_t end_pos = XFIXNUM (end); |
| 2468 | modify_text (pos, end_pos); | 2457 | modify_text (pos, end_pos); |
| 2469 | 2458 | ||
| 2470 | cnt = 0; | 2459 | ptrdiff_t characters_changed = 0; |
| 2471 | for (; pos < end_pos; ) | 2460 | |
| 2461 | while (pos < end_pos) | ||
| 2472 | { | 2462 | { |
| 2473 | unsigned char *p = BYTE_POS_ADDR (pos_byte); | 2463 | unsigned char *p = BYTE_POS_ADDR (pos_byte); |
| 2474 | unsigned char *str UNINIT; | 2464 | unsigned char *str UNINIT; |
| 2475 | unsigned char buf[MAX_MULTIBYTE_LENGTH]; | 2465 | unsigned char buf[MAX_MULTIBYTE_LENGTH]; |
| 2476 | int len, str_len; | 2466 | int len, oc; |
| 2477 | int oc; | ||
| 2478 | Lisp_Object val; | ||
| 2479 | 2467 | ||
| 2480 | if (multibyte) | 2468 | if (multibyte) |
| 2481 | oc = STRING_CHAR_AND_LENGTH (p, len); | 2469 | oc = STRING_CHAR_AND_LENGTH (p, len); |
| 2482 | else | 2470 | else |
| 2483 | oc = *p, len = 1; | 2471 | oc = *p, len = 1; |
| 2484 | if (oc < size) | 2472 | if (oc < translatable_chars) |
| 2485 | { | 2473 | { |
| 2486 | if (tt) | 2474 | int nc; /* New character. */ |
| 2475 | int str_len; | ||
| 2476 | Lisp_Object val; | ||
| 2477 | |||
| 2478 | if (STRINGP (table)) | ||
| 2487 | { | 2479 | { |
| 2488 | /* Reload as signal_after_change in last iteration may GC. */ | 2480 | /* Reload as signal_after_change in last iteration may GC. */ |
| 2489 | tt = SDATA (table); | 2481 | unsigned char *tt = SDATA (table); |
| 2482 | |||
| 2490 | if (string_multibyte) | 2483 | if (string_multibyte) |
| 2491 | { | 2484 | { |
| 2492 | str = tt + string_char_to_byte (table, oc); | 2485 | str = tt + string_char_to_byte (table, oc); |
| @@ -2535,7 +2528,8 @@ It returns the number of characters changed. */) | |||
| 2535 | /* This is less efficient, because it moves the gap, | 2528 | /* This is less efficient, because it moves the gap, |
| 2536 | but it should handle multibyte characters correctly. */ | 2529 | but it should handle multibyte characters correctly. */ |
| 2537 | string = make_multibyte_string ((char *) str, 1, str_len); | 2530 | string = make_multibyte_string ((char *) str, 1, str_len); |
| 2538 | replace_range (pos, pos + 1, string, 1, 0, 1, 0); | 2531 | replace_range (pos, pos + 1, string, |
| 2532 | true, false, true, false); | ||
| 2539 | len = str_len; | 2533 | len = str_len; |
| 2540 | } | 2534 | } |
| 2541 | else | 2535 | else |
| @@ -2546,12 +2540,10 @@ It returns the number of characters changed. */) | |||
| 2546 | signal_after_change (pos, 1, 1); | 2540 | signal_after_change (pos, 1, 1); |
| 2547 | update_compositions (pos, pos + 1, CHECK_BORDER); | 2541 | update_compositions (pos, pos + 1, CHECK_BORDER); |
| 2548 | } | 2542 | } |
| 2549 | ++cnt; | 2543 | characters_changed++; |
| 2550 | } | 2544 | } |
| 2551 | else if (nc < 0) | 2545 | else if (nc < 0) |
| 2552 | { | 2546 | { |
| 2553 | Lisp_Object string; | ||
| 2554 | |||
| 2555 | if (CONSP (val)) | 2547 | if (CONSP (val)) |
| 2556 | { | 2548 | { |
| 2557 | val = check_translation (pos, pos_byte, end_pos, val); | 2549 | val = check_translation (pos, pos_byte, end_pos, val); |
| @@ -2568,18 +2560,14 @@ It returns the number of characters changed. */) | |||
| 2568 | else | 2560 | else |
| 2569 | len = 1; | 2561 | len = 1; |
| 2570 | 2562 | ||
| 2571 | if (VECTORP (val)) | 2563 | Lisp_Object string |
| 2572 | { | 2564 | = (VECTORP (val) |
| 2573 | string = Fconcat (1, &val); | 2565 | ? Fconcat (1, &val) |
| 2574 | } | 2566 | : Fmake_string (make_fixnum (1), val, Qnil)); |
| 2575 | else | 2567 | replace_range (pos, pos + len, string, true, false, true, false); |
| 2576 | { | ||
| 2577 | string = Fmake_string (make_fixnum (1), val, Qnil); | ||
| 2578 | } | ||
| 2579 | replace_range (pos, pos + len, string, 1, 0, 1, 0); | ||
| 2580 | pos_byte += SBYTES (string); | 2568 | pos_byte += SBYTES (string); |
| 2581 | pos += SCHARS (string); | 2569 | pos += SCHARS (string); |
| 2582 | cnt += SCHARS (string); | 2570 | characters_changed += SCHARS (string); |
| 2583 | end_pos += SCHARS (string) - len; | 2571 | end_pos += SCHARS (string) - len; |
| 2584 | continue; | 2572 | continue; |
| 2585 | } | 2573 | } |
| @@ -2588,7 +2576,7 @@ It returns the number of characters changed. */) | |||
| 2588 | pos++; | 2576 | pos++; |
| 2589 | } | 2577 | } |
| 2590 | 2578 | ||
| 2591 | return make_fixnum (cnt); | 2579 | return make_fixnum (characters_changed); |
| 2592 | } | 2580 | } |
| 2593 | 2581 | ||
| 2594 | DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r", | 2582 | DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r", |