comparison src/editfns.c @ 54213:29d4d158e5eb

(Ftranslate_region): Handle multibyte chars in the arg TABLE correctly.
author Kenichi Handa <handa@m17n.org>
date Mon, 01 Mar 2004 06:19:10 +0000
parents a3fe35a8b56b
children a2f5ab3b6d1b
comparison
equal deleted inserted replaced
54212:ba850aa09d2d 54213:29d4d158e5eb
2739 2739
2740 DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0, 2740 DEFUN ("translate-region", Ftranslate_region, Stranslate_region, 3, 3, 0,
2741 doc: /* From START to END, translate characters according to TABLE. 2741 doc: /* From START to END, translate characters according to TABLE.
2742 TABLE is a string; the Nth character in it is the mapping 2742 TABLE is a string; the Nth character in it is the mapping
2743 for the character with code N. 2743 for the character with code N.
2744 This function does not alter multibyte characters.
2745 It returns the number of characters changed. */) 2744 It returns the number of characters changed. */)
2746 (start, end, table) 2745 (start, end, table)
2747 Lisp_Object start; 2746 Lisp_Object start;
2748 Lisp_Object end; 2747 Lisp_Object end;
2749 register Lisp_Object table; 2748 register Lisp_Object table;
2753 register int nc; /* New character. */ 2752 register int nc; /* New character. */
2754 int cnt; /* Number of changes made. */ 2753 int cnt; /* Number of changes made. */
2755 int size; /* Size of translate table. */ 2754 int size; /* Size of translate table. */
2756 int pos; 2755 int pos;
2757 int multibyte = !NILP (current_buffer->enable_multibyte_characters); 2756 int multibyte = !NILP (current_buffer->enable_multibyte_characters);
2757 int string_multibyte;
2758 2758
2759 validate_region (&start, &end); 2759 validate_region (&start, &end);
2760 CHECK_STRING (table); 2760 CHECK_STRING (table);
2761 2761
2762 size = SBYTES (table); 2762 if (multibyte != (SCHARS (table) < SBYTES (table)))
2763 table = (multibyte
2764 ? string_make_multibyte (table)
2765 : string_make_unibyte (table));
2766 string_multibyte = SCHARS (table) < SBYTES (table);
2767
2768 size = SCHARS (table);
2763 tt = SDATA (table); 2769 tt = SDATA (table);
2764 2770
2765 pos_byte = CHAR_TO_BYTE (XINT (start)); 2771 pos_byte = CHAR_TO_BYTE (XINT (start));
2766 stop = CHAR_TO_BYTE (XINT (end)); 2772 stop = CHAR_TO_BYTE (XINT (end));
2767 modify_region (current_buffer, XINT (start), XINT (end)); 2773 modify_region (current_buffer, XINT (start), XINT (end));
2769 2775
2770 cnt = 0; 2776 cnt = 0;
2771 for (; pos_byte < stop; ) 2777 for (; pos_byte < stop; )
2772 { 2778 {
2773 register unsigned char *p = BYTE_POS_ADDR (pos_byte); 2779 register unsigned char *p = BYTE_POS_ADDR (pos_byte);
2774 int len; 2780 unsigned char *str;
2781 int len, str_len;
2775 int oc; 2782 int oc;
2776 int pos_byte_next; 2783 int pos_byte_next;
2777 2784
2778 if (multibyte) 2785 if (multibyte)
2779 oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len); 2786 oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len);
2780 else 2787 else
2781 oc = *p, len = 1; 2788 oc = *p, len = 1;
2782 pos_byte_next = pos_byte + len; 2789 pos_byte_next = pos_byte + len;
2783 if (oc < size && len == 1) 2790 if (oc < size)
2784 { 2791 {
2785 nc = tt[oc]; 2792 if (string_multibyte)
2793 {
2794 str = tt + string_char_to_byte (table, oc);
2795 nc = STRING_CHAR_AND_LENGTH (str, MAX_MULTIBYTE_LENGTH, str_len);
2796 }
2797 else
2798 {
2799 str = tt + oc;
2800 nc = tt[oc], str_len = 1;
2801 }
2786 if (nc != oc) 2802 if (nc != oc)
2787 { 2803 {
2788 /* Take care of the case where the new character 2804 /* Take care of the case where the new character
2789 combines with neighboring bytes. */ 2805 combines with neighboring bytes. */
2790 if (!ASCII_BYTE_P (nc) 2806 if (len > 1 || str_len > 1)
2791 && (CHAR_HEAD_P (nc)
2792 ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))
2793 : (pos_byte > BEG_BYTE
2794 && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1)))))
2795 { 2807 {
2796 Lisp_Object string; 2808 Lisp_Object string;
2797 2809
2798 string = make_multibyte_string (tt + oc, 1, 1); 2810 string = make_multibyte_string (str, 1, str_len);
2799 /* This is less efficient, because it moves the gap, 2811 /* This is less efficient, because it moves the gap,
2800 but it handles combining correctly. */ 2812 but it handles combining correctly. */
2801 replace_range (pos, pos + 1, string, 2813 replace_range (pos, pos + 1, string,
2802 1, 0, 1); 2814 1, 0, 1);
2803 pos_byte_next = CHAR_TO_BYTE (pos); 2815 pos_byte_next = CHAR_TO_BYTE (pos);
2810 INC_POS (pos_byte_next); 2822 INC_POS (pos_byte_next);
2811 } 2823 }
2812 else 2824 else
2813 { 2825 {
2814 record_change (pos, 1); 2826 record_change (pos, 1);
2815 *p = nc; 2827 while (str_len-- > 0)
2828 *p++ = *str++;
2816 signal_after_change (pos, 1, 1); 2829 signal_after_change (pos, 1, 1);
2817 update_compositions (pos, pos + 1, CHECK_BORDER); 2830 update_compositions (pos, pos + 1, CHECK_BORDER);
2818 } 2831 }
2819 ++cnt; 2832 ++cnt;
2820 } 2833 }