diff options
| author | Richard M. Stallman | 1997-04-01 07:17:40 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1997-04-01 07:17:40 +0000 |
| commit | 3dbcf3f67b2180d4c8aec76ad0298aaacad9dab0 (patch) | |
| tree | 817c2d059493307dfa934f6efc3e323e6f2f9e4c /src | |
| parent | 4f1d7d31737310082d0e03b0007d0c25db175480 (diff) | |
| download | emacs-3dbcf3f67b2180d4c8aec76ad0298aaacad9dab0.tar.gz emacs-3dbcf3f67b2180d4c8aec76ad0298aaacad9dab0.zip | |
(Finsert_file_contents): Determine the character coding
before we see if REPLACE can be handled.
Do handle REPLACE even if code conversion is needed.
(Fcopy_file): Fix previous change.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fileio.c | 233 |
1 files changed, 198 insertions, 35 deletions
diff --git a/src/fileio.c b/src/fileio.c index cd8b0c19d0f..3e39154e6fa 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2131,7 +2131,7 @@ A prefix arg makes KEEP-TIME non-nil.") | |||
| 2131 | if (set_file_times (XSTRING (newname)->data, atime, mtime)) | 2131 | if (set_file_times (XSTRING (newname)->data, atime, mtime)) |
| 2132 | Fsignal (Qfile_date_error, | 2132 | Fsignal (Qfile_date_error, |
| 2133 | Fcons (build_string ("File already exists"), | 2133 | Fcons (build_string ("File already exists"), |
| 2134 | Fcons (absname, Qnil))); | 2134 | Fcons (newname, Qnil))); |
| 2135 | } | 2135 | } |
| 2136 | #ifndef MSDOS | 2136 | #ifndef MSDOS |
| 2137 | chmod (XSTRING (newname)->data, st.st_mode & 07777); | 2137 | chmod (XSTRING (newname)->data, st.st_mode & 07777); |
| @@ -3033,6 +3033,7 @@ This does code conversion according to the value of\n\ | |||
| 3033 | int not_regular = 0; | 3033 | int not_regular = 0; |
| 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 | 3037 | ||
| 3037 | if (current_buffer->base_buffer && ! NILP (visit)) | 3038 | if (current_buffer->base_buffer && ! NILP (visit)) |
| 3038 | error ("Cannot do file visiting in an indirect buffer"); | 3039 | error ("Cannot do file visiting in an indirect buffer"); |
| @@ -3141,20 +3142,49 @@ This does code conversion according to the value of\n\ | |||
| 3141 | error ("maximum buffer size exceeded"); | 3142 | error ("maximum buffer size exceeded"); |
| 3142 | } | 3143 | } |
| 3143 | 3144 | ||
| 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 | |||
| 3144 | /* If requested, replace the accessible part of the buffer | 3176 | /* If requested, replace the accessible part of the buffer |
| 3145 | with the file contents. Avoid replacing text at the | 3177 | with the file contents. Avoid replacing text at the |
| 3146 | beginning or end of the buffer that matches the file contents; | 3178 | beginning or end of the buffer that matches the file contents; |
| 3147 | that preserves markers pointing to the unchanged parts. */ | 3179 | that preserves markers pointing to the unchanged parts. |
| 3148 | if (!NILP (replace) && CODING_REQUIRE_CONVERSION (&coding)) | 3180 | |
| 3149 | { | 3181 | Here we implement this feature in an optimized way |
| 3150 | /* We have to decode the input, which means replace mode is | 3182 | for the case where code conversion is NOT needed. |
| 3151 | quite difficult. We give it up for the moment. */ | 3183 | The following if-statement handles the case of conversion |
| 3152 | replace = Qnil; | 3184 | in a less optimal way. */ |
| 3153 | del_range_1 (BEGV, ZV, 0); | 3185 | if (!NILP (replace) |
| 3154 | } | 3186 | && ! CODING_REQUIRE_CONVERSION (&coding)) |
| 3155 | if (!NILP (replace)) | ||
| 3156 | { | 3187 | { |
| 3157 | unsigned char buffer[1 << 14]; | ||
| 3158 | int same_at_start = BEGV; | 3188 | int same_at_start = BEGV; |
| 3159 | int same_at_end = ZV; | 3189 | int same_at_end = ZV; |
| 3160 | int overlap; | 3190 | int overlap; |
| @@ -3185,26 +3215,6 @@ This does code conversion according to the value of\n\ | |||
| 3185 | else if (nread == 0) | 3215 | else if (nread == 0) |
| 3186 | break; | 3216 | break; |
| 3187 | 3217 | ||
| 3188 | if (coding.type == coding_type_automatic) | ||
| 3189 | detect_coding (&coding, buffer, nread); | ||
| 3190 | if (CODING_REQUIRE_TEXT_CONVERSION (&coding)) | ||
| 3191 | /* We found that the file should be decoded somehow. | ||
| 3192 | Let's give up here. */ | ||
| 3193 | { | ||
| 3194 | giveup_match_end = 1; | ||
| 3195 | break; | ||
| 3196 | } | ||
| 3197 | |||
| 3198 | if (coding.eol_type == CODING_EOL_AUTOMATIC) | ||
| 3199 | detect_eol (&coding, buffer, nread); | ||
| 3200 | if (CODING_REQUIRE_EOL_CONVERSION (&coding)) | ||
| 3201 | /* We found that the format of eol should be decoded. | ||
| 3202 | Let's give up here. */ | ||
| 3203 | { | ||
| 3204 | giveup_match_end = 1; | ||
| 3205 | break; | ||
| 3206 | } | ||
| 3207 | |||
| 3208 | bufpos = 0; | 3218 | bufpos = 0; |
| 3209 | while (bufpos < nread && same_at_start < ZV | 3219 | while (bufpos < nread && same_at_start < ZV |
| 3210 | && FETCH_BYTE (same_at_start) == buffer[bufpos]) | 3220 | && FETCH_BYTE (same_at_start) == buffer[bufpos]) |
| @@ -3266,10 +3276,6 @@ This does code conversion according to the value of\n\ | |||
| 3266 | Otherwise loop around and scan the preceding bufferful. */ | 3276 | Otherwise loop around and scan the preceding bufferful. */ |
| 3267 | if (bufpos != 0) | 3277 | if (bufpos != 0) |
| 3268 | break; | 3278 | break; |
| 3269 | /* If display current starts at beginning of line, | ||
| 3270 | keep it that way. */ | ||
| 3271 | if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) | ||
| 3272 | XWINDOW (selected_window)->start_at_line_beg = Fbolp (); | ||
| 3273 | } | 3279 | } |
| 3274 | immediate_quit = 0; | 3280 | immediate_quit = 0; |
| 3275 | 3281 | ||
| @@ -3285,6 +3291,163 @@ This does code conversion according to the value of\n\ | |||
| 3285 | del_range_1 (same_at_start, same_at_end, 0); | 3291 | del_range_1 (same_at_start, same_at_end, 0); |
| 3286 | /* Insert from the file at the proper position. */ | 3292 | /* Insert from the file at the proper position. */ |
| 3287 | SET_PT (same_at_start); | 3293 | SET_PT (same_at_start); |
| 3294 | |||
| 3295 | /* If display currently starts at beginning of line, | ||
| 3296 | keep it that way. */ | ||
| 3297 | if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) | ||
| 3298 | XWINDOW (selected_window)->start_at_line_beg = Fbolp (); | ||
| 3299 | } | ||
| 3300 | |||
| 3301 | /* If requested, replace the accessible part of the buffer | ||
| 3302 | with the file contents. Avoid replacing text at the | ||
| 3303 | beginning or end of the buffer that matches the file contents; | ||
| 3304 | that preserves markers pointing to the unchanged parts. | ||
| 3305 | |||
| 3306 | Here we implement this feature for the case where code conversion | ||
| 3307 | is needed, in a simple way that needs a lot of memory. | ||
| 3308 | The preceding if-statement handles the case of no conversion | ||
| 3309 | in a more optimized way. */ | ||
| 3310 | if (!NILP (replace) && CODING_REQUIRE_CONVERSION (&coding)) | ||
| 3311 | { | ||
| 3312 | int same_at_start = BEGV; | ||
| 3313 | int same_at_end = ZV; | ||
| 3314 | int overlap; | ||
| 3315 | int bufpos; | ||
| 3316 | /* Make sure that the gap is large enough. */ | ||
| 3317 | int bufsize = 2 * st.st_size; | ||
| 3318 | unsigned char *conversion_buffer = (unsigned char *) malloc (bufsize); | ||
| 3319 | |||
| 3320 | /* First read the whole file, performing code conversion into | ||
| 3321 | CONVERSION_BUFFER. */ | ||
| 3322 | |||
| 3323 | total = st.st_size; /* Total bytes in the file. */ | ||
| 3324 | how_much = 0; /* Bytes read from file so far. */ | ||
| 3325 | inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */ | ||
| 3326 | unprocessed = 0; /* Bytes not processed in previous loop. */ | ||
| 3327 | |||
| 3328 | while (how_much < total) | ||
| 3329 | { | ||
| 3330 | /* try is reserved in some compilers (Microsoft C) */ | ||
| 3331 | int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed); | ||
| 3332 | char *destination = read_buf + unprocessed; | ||
| 3333 | int this; | ||
| 3334 | |||
| 3335 | /* Allow quitting out of the actual I/O. */ | ||
| 3336 | immediate_quit = 1; | ||
| 3337 | QUIT; | ||
| 3338 | this = read (fd, destination, trytry); | ||
| 3339 | immediate_quit = 0; | ||
| 3340 | |||
| 3341 | if (this < 0 || this + unprocessed == 0) | ||
| 3342 | { | ||
| 3343 | how_much = this; | ||
| 3344 | break; | ||
| 3345 | } | ||
| 3346 | |||
| 3347 | how_much += this; | ||
| 3348 | |||
| 3349 | if (CODING_REQUIRE_CONVERSION (&coding)) | ||
| 3350 | { | ||
| 3351 | int require, produced, consumed; | ||
| 3352 | |||
| 3353 | this += unprocessed; | ||
| 3354 | |||
| 3355 | /* If we are using more space than estimated, | ||
| 3356 | make CONVERSION_BUFFER bigger. */ | ||
| 3357 | require = decoding_buffer_size (&coding, this); | ||
| 3358 | if (inserted + require + 2 * (total - how_much) > bufsize) | ||
| 3359 | { | ||
| 3360 | bufsize = inserted + require + 2 * (total - how_much); | ||
| 3361 | conversion_buffer = (unsigned char *) realloc (conversion_buffer, bufsize); | ||
| 3362 | } | ||
| 3363 | |||
| 3364 | /* Convert this batch with results in CONVERSION_BUFFER. */ | ||
| 3365 | if (how_much >= total) /* This is the last block. */ | ||
| 3366 | coding.last_block = 1; | ||
| 3367 | produced = decode_coding (&coding, read_buf, | ||
| 3368 | conversion_buffer + inserted, | ||
| 3369 | this, bufsize - inserted, | ||
| 3370 | &consumed); | ||
| 3371 | |||
| 3372 | /* Save for next iteration whatever we didn't convert. */ | ||
| 3373 | unprocessed = this - consumed; | ||
| 3374 | bcopy (read_buf + consumed, read_buf, unprocessed); | ||
| 3375 | this = produced; | ||
| 3376 | } | ||
| 3377 | |||
| 3378 | inserted += this; | ||
| 3379 | } | ||
| 3380 | |||
| 3381 | /* At this point, INSERTED is how many characters | ||
| 3382 | are present in CONVERSION_BUFFER. | ||
| 3383 | HOW_MUCH should equal TOTAL, | ||
| 3384 | or should be <= 0 if we couldn't read the file. */ | ||
| 3385 | |||
| 3386 | if (how_much < 0) | ||
| 3387 | { | ||
| 3388 | free (conversion_buffer); | ||
| 3389 | |||
| 3390 | if (how_much == -1) | ||
| 3391 | error ("IO error reading %s: %s", | ||
| 3392 | XSTRING (filename)->data, strerror (errno)); | ||
| 3393 | else if (how_much == -2) | ||
| 3394 | error ("maximum buffer size exceeded"); | ||
| 3395 | } | ||
| 3396 | |||
| 3397 | /* Compare the beginning of the converted file | ||
| 3398 | with the buffer text. */ | ||
| 3399 | |||
| 3400 | bufpos = 0; | ||
| 3401 | while (bufpos < inserted && same_at_start < same_at_end | ||
| 3402 | && FETCH_BYTE (same_at_start) == conversion_buffer[bufpos]) | ||
| 3403 | same_at_start++, bufpos++; | ||
| 3404 | |||
| 3405 | /* If the file matches the buffer completely, | ||
| 3406 | there's no need to replace anything. */ | ||
| 3407 | |||
| 3408 | if (bufpos == inserted) | ||
| 3409 | { | ||
| 3410 | free (conversion_buffer); | ||
| 3411 | close (fd); | ||
| 3412 | specpdl_ptr--; | ||
| 3413 | /* Truncate the buffer to the size of the file. */ | ||
| 3414 | del_range_1 (same_at_start, same_at_end, 0); | ||
| 3415 | goto handled; | ||
| 3416 | } | ||
| 3417 | |||
| 3418 | /* Scan this bufferful from the end, comparing with | ||
| 3419 | the Emacs buffer. */ | ||
| 3420 | bufpos = inserted; | ||
| 3421 | |||
| 3422 | /* Compare with same_at_start to avoid counting some buffer text | ||
| 3423 | as matching both at the file's beginning and at the end. */ | ||
| 3424 | while (bufpos > 0 && same_at_end > same_at_start | ||
| 3425 | && FETCH_BYTE (same_at_end - 1) == conversion_buffer[bufpos - 1]) | ||
| 3426 | same_at_end--, bufpos--; | ||
| 3427 | |||
| 3428 | /* Don't try to reuse the same piece of text twice. */ | ||
| 3429 | overlap = same_at_start - BEGV - (same_at_end + inserted - ZV); | ||
| 3430 | if (overlap > 0) | ||
| 3431 | same_at_end += overlap; | ||
| 3432 | |||
| 3433 | /* Replace the chars that we need to replace, | ||
| 3434 | and update INSERTED to equal the number of bytes | ||
| 3435 | we are taking from the file. */ | ||
| 3436 | inserted -= (Z - same_at_end) + (same_at_start - BEG); | ||
| 3437 | move_gap (same_at_start); | ||
| 3438 | del_range_1 (same_at_start, same_at_end, 0); | ||
| 3439 | make_gap (inserted); | ||
| 3440 | insert (conversion_buffer + same_at_start - BEG, inserted); | ||
| 3441 | |||
| 3442 | free (conversion_buffer); | ||
| 3443 | close (fd); | ||
| 3444 | specpdl_ptr--; | ||
| 3445 | |||
| 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; | ||
| 3288 | } | 3451 | } |
| 3289 | 3452 | ||
| 3290 | total = XINT (end) - XINT (beg); | 3453 | total = XINT (end) - XINT (beg); |