diff options
| author | Richard M. Stallman | 1997-04-02 05:03:06 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1997-04-02 05:03:06 +0000 |
| commit | 727a0b4a0f92e32aa57f5c1567a6ec7993e4d610 (patch) | |
| tree | b09b17098bb9d4c68feba4e855b8c2d0209d0f18 /src | |
| parent | 0118dcd34323b01bb6472298df0741030eceb8a4 (diff) | |
| download | emacs-727a0b4a0f92e32aa57f5c1567a6ec7993e4d610.tar.gz emacs-727a0b4a0f92e32aa57f5c1567a6ec7993e4d610.zip | |
(Finsert_file_contents): When handling REPLACE,
first try comparing block by block; if we discover a need for
nontrivial code conversion, give up and try convert-whole-file method.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 132 |
1 files changed, 77 insertions, 55 deletions
diff --git a/src/fileio.c b/src/fileio.c index 3e39154e6fa..65219833360 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -3034,6 +3034,7 @@ This does code conversion according to the value of\n\ | |||
| 3034 | char read_buf[READ_BUF_SIZE]; | 3034 | char read_buf[READ_BUF_SIZE]; |
| 3035 | struct coding_system coding; | 3035 | struct coding_system coding; |
| 3036 | unsigned char buffer[1 << 14]; | 3036 | unsigned char buffer[1 << 14]; |
| 3037 | int replace_handled = 0; | ||
| 3037 | 3038 | ||
| 3038 | if (current_buffer->base_buffer && ! NILP (visit)) | 3039 | if (current_buffer->base_buffer && ! NILP (visit)) |
| 3039 | error ("Cannot do file visiting in an indirect buffer"); | 3040 | error ("Cannot do file visiting in an indirect buffer"); |
| @@ -3142,37 +3143,6 @@ This does code conversion according to the value of\n\ | |||
| 3142 | error ("maximum buffer size exceeded"); | 3143 | error ("maximum buffer size exceeded"); |
| 3143 | } | 3144 | } |
| 3144 | 3145 | ||
| 3145 | /* Try to determine the character coding now, | ||
| 3146 | hoping we can recognize that no coding is used | ||
| 3147 | and thus enable the REPLACE feature to work. */ | ||
| 3148 | if (!NILP (replace) && (coding.type == coding_type_automatic | ||
| 3149 | || coding.eol_type == CODING_EOL_AUTOMATIC)) | ||
| 3150 | { | ||
| 3151 | int nread, bufpos; | ||
| 3152 | |||
| 3153 | nread = read (fd, buffer, sizeof buffer); | ||
| 3154 | if (nread < 0) | ||
| 3155 | error ("IO error reading %s: %s", | ||
| 3156 | XSTRING (filename)->data, strerror (errno)); | ||
| 3157 | else if (nread > 0) | ||
| 3158 | { | ||
| 3159 | if (coding.type == coding_type_automatic) | ||
| 3160 | detect_coding (&coding, buffer, nread); | ||
| 3161 | if (coding.eol_type == CODING_EOL_AUTOMATIC) | ||
| 3162 | detect_eol (&coding, buffer, nread); | ||
| 3163 | if (lseek (fd, 0, 0) < 0) | ||
| 3164 | report_file_error ("Setting file position", | ||
| 3165 | Fcons (filename, Qnil)); | ||
| 3166 | /* If we still haven't found anything other than | ||
| 3167 | "automatic", change to "no conversion" | ||
| 3168 | so that the replace feature will work. */ | ||
| 3169 | if (coding.type == coding_type_automatic) | ||
| 3170 | coding.type = coding_type_no_conversion; | ||
| 3171 | if (coding.eol_type == CODING_EOL_AUTOMATIC) | ||
| 3172 | coding.eol_type = CODING_EOL_LF; | ||
| 3173 | } | ||
| 3174 | } | ||
| 3175 | |||
| 3176 | /* If requested, replace the accessible part of the buffer | 3146 | /* If requested, replace the accessible part of the buffer |
| 3177 | with the file contents. Avoid replacing text at the | 3147 | with the file contents. Avoid replacing text at the |
| 3178 | beginning or end of the buffer that matches the file contents; | 3148 | beginning or end of the buffer that matches the file contents; |
| @@ -3181,16 +3151,25 @@ This does code conversion according to the value of\n\ | |||
| 3181 | Here we implement this feature in an optimized way | 3151 | Here we implement this feature in an optimized way |
| 3182 | for the case where code conversion is NOT needed. | 3152 | for the case where code conversion is NOT needed. |
| 3183 | The following if-statement handles the case of conversion | 3153 | The following if-statement handles the case of conversion |
| 3184 | in a less optimal way. */ | 3154 | in a less optimal way. |
| 3155 | |||
| 3156 | If the code conversion is "automatic" then we try using this | ||
| 3157 | method and hope for the best. | ||
| 3158 | But if we discover the need for conversion, we give up on this method | ||
| 3159 | and let the following if-statement handle the replace job. */ | ||
| 3185 | if (!NILP (replace) | 3160 | if (!NILP (replace) |
| 3186 | && ! CODING_REQUIRE_CONVERSION (&coding)) | 3161 | && (! CODING_REQUIRE_CONVERSION (&coding) |
| 3162 | || (coding.type == coding_type_automatic | ||
| 3163 | && ! CODING_REQUIRE_TEXT_CONVERSION (&coding)) | ||
| 3164 | || (coding.eol_type == CODING_EOL_AUTOMATIC | ||
| 3165 | && ! CODING_REQUIRE_EOL_CONVERSION (&coding)))) | ||
| 3187 | { | 3166 | { |
| 3188 | int same_at_start = BEGV; | 3167 | int same_at_start = BEGV; |
| 3189 | int same_at_end = ZV; | 3168 | int same_at_end = ZV; |
| 3190 | int overlap; | 3169 | int overlap; |
| 3191 | /* There is still a possibility we will find the need to do code | 3170 | /* There is still a possibility we will find the need to do code |
| 3192 | conversion. If that happens, we set this variable to 1 to | 3171 | conversion. If that happens, we set this variable to 1 to |
| 3193 | give up on the REPLACE feature. */ | 3172 | give up on handling REPLACE in the optimized way. */ |
| 3194 | int giveup_match_end = 0; | 3173 | int giveup_match_end = 0; |
| 3195 | 3174 | ||
| 3196 | if (XINT (beg) != 0) | 3175 | if (XINT (beg) != 0) |
| @@ -3215,6 +3194,26 @@ This does code conversion according to the value of\n\ | |||
| 3215 | else if (nread == 0) | 3194 | else if (nread == 0) |
| 3216 | break; | 3195 | break; |
| 3217 | 3196 | ||
| 3197 | if (coding.type == coding_type_automatic) | ||
| 3198 | detect_coding (&coding, buffer, nread); | ||
| 3199 | if (CODING_REQUIRE_TEXT_CONVERSION (&coding)) | ||
| 3200 | /* We found that the file should be decoded somehow. | ||
| 3201 | Let's give up here. */ | ||
| 3202 | { | ||
| 3203 | giveup_match_end = 1; | ||
| 3204 | break; | ||
| 3205 | } | ||
| 3206 | |||
| 3207 | if (coding.eol_type == CODING_EOL_AUTOMATIC) | ||
| 3208 | detect_eol (&coding, buffer, nread); | ||
| 3209 | if (CODING_REQUIRE_EOL_CONVERSION (&coding)) | ||
| 3210 | /* We found that the format of eol should be decoded. | ||
| 3211 | Let's give up here. */ | ||
| 3212 | { | ||
| 3213 | giveup_match_end = 1; | ||
| 3214 | break; | ||
| 3215 | } | ||
| 3216 | |||
| 3218 | bufpos = 0; | 3217 | bufpos = 0; |
| 3219 | while (bufpos < nread && same_at_start < ZV | 3218 | while (bufpos < nread && same_at_start < ZV |
| 3220 | && FETCH_BYTE (same_at_start) == buffer[bufpos]) | 3219 | && FETCH_BYTE (same_at_start) == buffer[bufpos]) |
| @@ -3272,30 +3271,46 @@ This does code conversion according to the value of\n\ | |||
| 3272 | while (bufpos > 0 && same_at_end > same_at_start | 3271 | while (bufpos > 0 && same_at_end > same_at_start |
| 3273 | && FETCH_BYTE (same_at_end - 1) == buffer[bufpos - 1]) | 3272 | && FETCH_BYTE (same_at_end - 1) == buffer[bufpos - 1]) |
| 3274 | same_at_end--, bufpos--; | 3273 | same_at_end--, bufpos--; |
| 3274 | |||
| 3275 | /* If we found a discrepancy, stop the scan. | 3275 | /* If we found a discrepancy, stop the scan. |
| 3276 | Otherwise loop around and scan the preceding bufferful. */ | 3276 | Otherwise loop around and scan the preceding bufferful. */ |
| 3277 | if (bufpos != 0) | 3277 | if (bufpos != 0) |
| 3278 | break; | 3278 | { |
| 3279 | /* If this discrepancy is because of code conversion, | ||
| 3280 | we cannot use this method; giveup and try the other. */ | ||
| 3281 | if (same_at_end > same_at_start | ||
| 3282 | && FETCH_BYTE (same_at_end - 1) >= 0200 | ||
| 3283 | && ! NILP (current_buffer->enable_multibyte_characters)) | ||
| 3284 | giveup_match_end = 1; | ||
| 3285 | break; | ||
| 3286 | } | ||
| 3279 | } | 3287 | } |
| 3280 | immediate_quit = 0; | 3288 | immediate_quit = 0; |
| 3281 | 3289 | ||
| 3282 | /* Don't try to reuse the same piece of text twice. */ | 3290 | if (! giveup_match_end) |
| 3283 | overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV); | 3291 | { |
| 3284 | if (overlap > 0) | 3292 | /* We win! We can handle REPLACE the optimized way. */ |
| 3285 | same_at_end += overlap; | ||
| 3286 | 3293 | ||
| 3287 | /* Arrange to read only the nonmatching middle part of the file. */ | 3294 | /* Don't try to reuse the same piece of text twice. */ |
| 3288 | XSETFASTINT (beg, XINT (beg) + (same_at_start - BEGV)); | 3295 | overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV); |
| 3289 | XSETFASTINT (end, XINT (end) - (ZV - same_at_end)); | 3296 | if (overlap > 0) |
| 3297 | same_at_end += overlap; | ||
| 3290 | 3298 | ||
| 3291 | del_range_1 (same_at_start, same_at_end, 0); | 3299 | /* Arrange to read only the nonmatching middle part of the file. */ |
| 3292 | /* Insert from the file at the proper position. */ | 3300 | XSETFASTINT (beg, XINT (beg) + (same_at_start - BEGV)); |
| 3293 | SET_PT (same_at_start); | 3301 | XSETFASTINT (end, XINT (end) - (ZV - same_at_end)); |
| 3294 | 3302 | ||
| 3295 | /* If display currently starts at beginning of line, | 3303 | del_range_1 (same_at_start, same_at_end, 0); |
| 3296 | keep it that way. */ | 3304 | /* Insert from the file at the proper position. */ |
| 3297 | if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) | 3305 | SET_PT (same_at_start); |
| 3298 | XWINDOW (selected_window)->start_at_line_beg = Fbolp (); | 3306 | |
| 3307 | /* If display currently starts at beginning of line, | ||
| 3308 | keep it that way. */ | ||
| 3309 | if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) | ||
| 3310 | XWINDOW (selected_window)->start_at_line_beg = Fbolp (); | ||
| 3311 | |||
| 3312 | replace_handled = 1; | ||
| 3313 | } | ||
| 3299 | } | 3314 | } |
| 3300 | 3315 | ||
| 3301 | /* If requested, replace the accessible part of the buffer | 3316 | /* If requested, replace the accessible part of the buffer |
| @@ -3307,7 +3322,7 @@ This does code conversion according to the value of\n\ | |||
| 3307 | is needed, in a simple way that needs a lot of memory. | 3322 | is needed, in a simple way that needs a lot of memory. |
| 3308 | The preceding if-statement handles the case of no conversion | 3323 | The preceding if-statement handles the case of no conversion |
| 3309 | in a more optimized way. */ | 3324 | in a more optimized way. */ |
| 3310 | if (!NILP (replace) && CODING_REQUIRE_CONVERSION (&coding)) | 3325 | if (!NILP (replace) && ! replace_handled) |
| 3311 | { | 3326 | { |
| 3312 | int same_at_start = BEGV; | 3327 | int same_at_start = BEGV; |
| 3313 | int same_at_end = ZV; | 3328 | int same_at_end = ZV; |
| @@ -3320,6 +3335,13 @@ This does code conversion according to the value of\n\ | |||
| 3320 | /* First read the whole file, performing code conversion into | 3335 | /* First read the whole file, performing code conversion into |
| 3321 | CONVERSION_BUFFER. */ | 3336 | CONVERSION_BUFFER. */ |
| 3322 | 3337 | ||
| 3338 | if (lseek (fd, XINT (beg), 0) < 0) | ||
| 3339 | { | ||
| 3340 | free (conversion_buffer); | ||
| 3341 | report_file_error ("Setting file position", | ||
| 3342 | Fcons (filename, Qnil)); | ||
| 3343 | } | ||
| 3344 | |||
| 3323 | total = st.st_size; /* Total bytes in the file. */ | 3345 | total = st.st_size; /* Total bytes in the file. */ |
| 3324 | how_much = 0; /* Bytes read from file so far. */ | 3346 | how_much = 0; /* Bytes read from file so far. */ |
| 3325 | inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */ | 3347 | inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */ |
| @@ -3430,23 +3452,23 @@ This does code conversion according to the value of\n\ | |||
| 3430 | if (overlap > 0) | 3452 | if (overlap > 0) |
| 3431 | same_at_end += overlap; | 3453 | same_at_end += overlap; |
| 3432 | 3454 | ||
| 3455 | /* If display currently starts at beginning of line, | ||
| 3456 | keep it that way. */ | ||
| 3457 | if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) | ||
| 3458 | XWINDOW (selected_window)->start_at_line_beg = Fbolp (); | ||
| 3459 | |||
| 3433 | /* Replace the chars that we need to replace, | 3460 | /* Replace the chars that we need to replace, |
| 3434 | and update INSERTED to equal the number of bytes | 3461 | and update INSERTED to equal the number of bytes |
| 3435 | we are taking from the file. */ | 3462 | we are taking from the file. */ |
| 3436 | inserted -= (Z - same_at_end) + (same_at_start - BEG); | 3463 | inserted -= (Z - same_at_end) + (same_at_start - BEG); |
| 3437 | move_gap (same_at_start); | 3464 | move_gap (same_at_start); |
| 3438 | del_range_1 (same_at_start, same_at_end, 0); | 3465 | del_range_1 (same_at_start, same_at_end, 0); |
| 3439 | make_gap (inserted); | ||
| 3440 | insert (conversion_buffer + same_at_start - BEG, inserted); | 3466 | insert (conversion_buffer + same_at_start - BEG, inserted); |
| 3441 | 3467 | ||
| 3442 | free (conversion_buffer); | 3468 | free (conversion_buffer); |
| 3443 | close (fd); | 3469 | close (fd); |
| 3444 | specpdl_ptr--; | 3470 | specpdl_ptr--; |
| 3445 | 3471 | ||
| 3446 | /* If display currently starts at beginning of line, | ||
| 3447 | keep it that way. */ | ||
| 3448 | if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) | ||
| 3449 | XWINDOW (selected_window)->start_at_line_beg = Fbolp (); | ||
| 3450 | goto handled; | 3472 | goto handled; |
| 3451 | } | 3473 | } |
| 3452 | 3474 | ||