diff options
| author | Kenichi Handa | 1998-10-27 03:54:13 +0000 |
|---|---|---|
| committer | Kenichi Handa | 1998-10-27 03:54:13 +0000 |
| commit | a3360ff9150045b8e379bfc856c47ba872ddb0ce (patch) | |
| tree | daf8e0edcba4553b2625d1caeb6a5e6872c50725 /src | |
| parent | b413f89564f18ef411c8fe8f4ec157e41c29c01d (diff) | |
| download | emacs-a3360ff9150045b8e379bfc856c47ba872ddb0ce.tar.gz emacs-a3360ff9150045b8e379bfc856c47ba872ddb0ce.zip | |
(Fsubst_char_in_region): Correctly handle the case
that byte combining before happens.
(Ftranslate_region): Likewise.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 98 |
1 files changed, 69 insertions, 29 deletions
diff --git a/src/editfns.c b/src/editfns.c index a0c09ebf095..b6302ca05f2 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -1938,6 +1938,7 @@ Both characters must have the same length of multi-byte form.") | |||
| 1938 | int changed = 0; | 1938 | int changed = 0; |
| 1939 | unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p; | 1939 | unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p; |
| 1940 | int count = specpdl_ptr - specpdl; | 1940 | int count = specpdl_ptr - specpdl; |
| 1941 | int maybe_byte_combining = 0; | ||
| 1941 | 1942 | ||
| 1942 | validate_region (&start, &end); | 1943 | validate_region (&start, &end); |
| 1943 | CHECK_NUMBER (fromchar, 2); | 1944 | CHECK_NUMBER (fromchar, 2); |
| @@ -1948,6 +1949,11 @@ Both characters must have the same length of multi-byte form.") | |||
| 1948 | len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr); | 1949 | len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr); |
| 1949 | if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len) | 1950 | if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len) |
| 1950 | error ("Characters in subst-char-in-region have different byte-lengths"); | 1951 | error ("Characters in subst-char-in-region have different byte-lengths"); |
| 1952 | if (len == 1) | ||
| 1953 | /* If *TOSTR is in the range 0x80..0x9F, it may be combined | ||
| 1954 | with the after bytes. If it is in the range 0xA0..0xFF, it | ||
| 1955 | may be combined with the before bytes. */ | ||
| 1956 | maybe_byte_combining = !ASCII_BYTE_P (*tostr); | ||
| 1951 | } | 1957 | } |
| 1952 | else | 1958 | else |
| 1953 | { | 1959 | { |
| @@ -1980,13 +1986,17 @@ Both characters must have the same length of multi-byte form.") | |||
| 1980 | stop = min (stop, GPT_BYTE); | 1986 | stop = min (stop, GPT_BYTE); |
| 1981 | while (1) | 1987 | while (1) |
| 1982 | { | 1988 | { |
| 1989 | int pos_byte_next = pos_byte; | ||
| 1990 | |||
| 1983 | if (pos_byte >= stop) | 1991 | if (pos_byte >= stop) |
| 1984 | { | 1992 | { |
| 1985 | if (pos_byte >= end_byte) break; | 1993 | if (pos_byte >= end_byte) break; |
| 1986 | stop = end_byte; | 1994 | stop = end_byte; |
| 1987 | } | 1995 | } |
| 1988 | p = BYTE_POS_ADDR (pos_byte); | 1996 | p = BYTE_POS_ADDR (pos_byte); |
| 1989 | if (p[0] == fromstr[0] | 1997 | INC_POS (pos_byte_next); |
| 1998 | if (pos_byte_next - pos_byte == len | ||
| 1999 | && p[0] == fromstr[0] | ||
| 1990 | && (len == 1 | 2000 | && (len == 1 |
| 1991 | || (p[1] == fromstr[1] | 2001 | || (p[1] == fromstr[1] |
| 1992 | && (len == 2 || (p[2] == fromstr[2] | 2002 | && (len == 2 || (p[2] == fromstr[2] |
| @@ -2009,14 +2019,11 @@ Both characters must have the same length of multi-byte form.") | |||
| 2009 | 2019 | ||
| 2010 | /* Take care of the case where the new character | 2020 | /* Take care of the case where the new character |
| 2011 | combines with neighboring bytes. */ | 2021 | combines with neighboring bytes. */ |
| 2012 | if (len == 1 | 2022 | if (maybe_byte_combining |
| 2013 | && ((! CHAR_HEAD_P (tostr[0]) | 2023 | && (CHAR_HEAD_P (*tostr) |
| 2014 | && pos_byte > BEGV_BYTE | 2024 | ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1)) |
| 2015 | && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))) | 2025 | : (pos_byte > BEGV_BYTE |
| 2016 | || | 2026 | && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))))) |
| 2017 | (! ASCII_BYTE_P (tostr[0]) | ||
| 2018 | && pos_byte + 1 < ZV_BYTE | ||
| 2019 | && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1))))) | ||
| 2020 | { | 2027 | { |
| 2021 | Lisp_Object tem, string; | 2028 | Lisp_Object tem, string; |
| 2022 | 2029 | ||
| @@ -2025,15 +2032,24 @@ Both characters must have the same length of multi-byte form.") | |||
| 2025 | tem = current_buffer->undo_list; | 2032 | tem = current_buffer->undo_list; |
| 2026 | GCPRO1 (tem); | 2033 | GCPRO1 (tem); |
| 2027 | 2034 | ||
| 2028 | /* Make a multibyte string containing this | 2035 | /* Make a multibyte string containing this single-byte |
| 2029 | single-byte character. */ | 2036 | character. */ |
| 2030 | string = Fmake_string (make_number (1), | 2037 | string = make_multibyte_string (tostr, 1, 1); |
| 2031 | make_number (tochar)); | ||
| 2032 | SET_STRING_BYTES (XSTRING (string), 1); | ||
| 2033 | /* replace_range is less efficient, because it moves the gap, | 2038 | /* replace_range is less efficient, because it moves the gap, |
| 2034 | but it handles combining correctly. */ | 2039 | but it handles combining correctly. */ |
| 2035 | replace_range (pos, pos + 1, string, | 2040 | replace_range (pos, pos + 1, string, |
| 2036 | 0, 0, 1); | 2041 | 0, 0, 1); |
| 2042 | pos_byte_next = CHAR_TO_BYTE (pos); | ||
| 2043 | if (pos_byte_next > pos_byte) | ||
| 2044 | /* Before combining happened. We should not increment | ||
| 2045 | POS because now it points the next character. */ | ||
| 2046 | pos_byte = pos_byte_next; | ||
| 2047 | else | ||
| 2048 | { | ||
| 2049 | pos++; | ||
| 2050 | INC_POS (pos_byte_next); | ||
| 2051 | } | ||
| 2052 | |||
| 2037 | if (! NILP (noundo)) | 2053 | if (! NILP (noundo)) |
| 2038 | current_buffer->undo_list = tem; | 2054 | current_buffer->undo_list = tem; |
| 2039 | 2055 | ||
| @@ -2044,9 +2060,15 @@ Both characters must have the same length of multi-byte form.") | |||
| 2044 | if (NILP (noundo)) | 2060 | if (NILP (noundo)) |
| 2045 | record_change (pos, 1); | 2061 | record_change (pos, 1); |
| 2046 | for (i = 0; i < len; i++) *p++ = tostr[i]; | 2062 | for (i = 0; i < len; i++) *p++ = tostr[i]; |
| 2063 | pos_byte = pos_byte_next; | ||
| 2064 | pos++; | ||
| 2047 | } | 2065 | } |
| 2048 | } | 2066 | } |
| 2049 | INC_BOTH (pos, pos_byte); | 2067 | else |
| 2068 | { | ||
| 2069 | pos_byte = pos_byte_next; | ||
| 2070 | pos++; | ||
| 2071 | } | ||
| 2050 | } | 2072 | } |
| 2051 | 2073 | ||
| 2052 | if (changed) | 2074 | if (changed) |
| @@ -2092,8 +2114,10 @@ It returns the number of characters changed.") | |||
| 2092 | register unsigned char *p = BYTE_POS_ADDR (pos_byte); | 2114 | register unsigned char *p = BYTE_POS_ADDR (pos_byte); |
| 2093 | int len; | 2115 | int len; |
| 2094 | int oc; | 2116 | int oc; |
| 2117 | int pos_byte_next; | ||
| 2095 | 2118 | ||
| 2096 | oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len); | 2119 | oc = STRING_CHAR_AND_LENGTH (p, stop - pos_byte, len); |
| 2120 | pos_byte_next = pos_byte + len; | ||
| 2097 | if (oc < size && len == 1) | 2121 | if (oc < size && len == 1) |
| 2098 | { | 2122 | { |
| 2099 | nc = tt[oc]; | 2123 | nc = tt[oc]; |
| @@ -2101,36 +2125,52 @@ It returns the number of characters changed.") | |||
| 2101 | { | 2125 | { |
| 2102 | /* Take care of the case where the new character | 2126 | /* Take care of the case where the new character |
| 2103 | combines with neighboring bytes. */ | 2127 | combines with neighboring bytes. */ |
| 2104 | if ((! CHAR_HEAD_P (nc) | 2128 | if (!ASCII_BYTE_P (nc) |
| 2105 | && pos_byte > BEGV_BYTE | 2129 | && (CHAR_HEAD_P (nc) |
| 2106 | && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))) | 2130 | ? ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1)) |
| 2107 | || | 2131 | : (pos_byte > BEGV_BYTE |
| 2108 | (! ASCII_BYTE_P (nc) | 2132 | && ! ASCII_BYTE_P (FETCH_BYTE (pos_byte - 1))))) |
| 2109 | && pos_byte + 1 < ZV_BYTE | ||
| 2110 | && ! CHAR_HEAD_P (FETCH_BYTE (pos_byte + 1)))) | ||
| 2111 | { | 2133 | { |
| 2112 | Lisp_Object string; | 2134 | Lisp_Object string; |
| 2113 | 2135 | ||
| 2114 | string = Fmake_string (make_number (1), | 2136 | string = make_multibyte_string (tt + oc, 1, 1); |
| 2115 | make_number (nc)); | ||
| 2116 | SET_STRING_BYTES (XSTRING (string), 1); | ||
| 2117 | |||
| 2118 | /* This is less efficient, because it moves the gap, | 2137 | /* This is less efficient, because it moves the gap, |
| 2119 | but it handles combining correctly. */ | 2138 | but it handles combining correctly. */ |
| 2120 | replace_range (pos, pos + 1, string, | 2139 | replace_range (pos, pos + 1, string, |
| 2121 | 1, 0, 0); | 2140 | 1, 0, 1); |
| 2141 | pos_byte_next = CHAR_TO_BYTE (pos); | ||
| 2142 | if (pos_byte_next > pos_byte) | ||
| 2143 | /* Before combining happened. We should not | ||
| 2144 | increment POS because now it points the next | ||
| 2145 | character. */ | ||
| 2146 | pos_byte = pos_byte_next; | ||
| 2147 | else | ||
| 2148 | { | ||
| 2149 | pos++; | ||
| 2150 | INC_POS (pos_byte_next); | ||
| 2151 | } | ||
| 2122 | } | 2152 | } |
| 2123 | else | 2153 | else |
| 2124 | { | 2154 | { |
| 2125 | record_change (pos, 1); | 2155 | record_change (pos, 1); |
| 2126 | *p = nc; | 2156 | *p = nc; |
| 2127 | signal_after_change (pos, 1, 1); | 2157 | signal_after_change (pos, 1, 1); |
| 2158 | pos_byte++; | ||
| 2159 | pos++; | ||
| 2128 | } | 2160 | } |
| 2129 | ++cnt; | 2161 | ++cnt; |
| 2130 | } | 2162 | } |
| 2163 | else | ||
| 2164 | { | ||
| 2165 | pos_byte++; | ||
| 2166 | pos++; | ||
| 2167 | } | ||
| 2168 | } | ||
| 2169 | else | ||
| 2170 | { | ||
| 2171 | pos_byte += len; | ||
| 2172 | pos++; | ||
| 2131 | } | 2173 | } |
| 2132 | pos_byte += len; | ||
| 2133 | pos++; | ||
| 2134 | } | 2174 | } |
| 2135 | 2175 | ||
| 2136 | return make_number (cnt); | 2176 | return make_number (cnt); |