aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2019-01-13 15:45:14 -0800
committerPaul Eggert2019-01-13 15:46:44 -0800
commit1a722e888454a0cb24dffc35455467688b4b4c60 (patch)
tree715e89cb287001ec3857aacbe988bf5ec0d9f6fd /src
parent800d3815e4a82f83b98cf87b205dcfdb0670907f (diff)
downloademacs-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.c82
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.
2433TABLE is a string or a char-table; the Nth character in it is the 2433TABLE is a string or a char-table; the Nth character in it is the
2434mapping for the character with code N. 2434mapping for the character with code N.
2435It returns the number of characters changed. */) 2435It 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
2594DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r", 2582DEFUN ("delete-region", Fdelete_region, Sdelete_region, 2, 2, "r",