From 727a0b4a0f92e32aa57f5c1567a6ec7993e4d610 Mon Sep 17 00:00:00 2001 From: "Richard M. Stallman" Date: Wed, 2 Apr 1997 05:03:06 +0000 Subject: [PATCH] (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. --- src/fileio.c | 132 ++++++++++++++++++++++++++++++--------------------- 1 file 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\ char read_buf[READ_BUF_SIZE]; struct coding_system coding; unsigned char buffer[1 << 14]; + int replace_handled = 0; if (current_buffer->base_buffer && ! NILP (visit)) error ("Cannot do file visiting in an indirect buffer"); @@ -3142,37 +3143,6 @@ This does code conversion according to the value of\n\ error ("maximum buffer size exceeded"); } - /* Try to determine the character coding now, - hoping we can recognize that no coding is used - and thus enable the REPLACE feature to work. */ - if (!NILP (replace) && (coding.type == coding_type_automatic - || coding.eol_type == CODING_EOL_AUTOMATIC)) - { - int nread, bufpos; - - nread = read (fd, buffer, sizeof buffer); - if (nread < 0) - error ("IO error reading %s: %s", - XSTRING (filename)->data, strerror (errno)); - else if (nread > 0) - { - if (coding.type == coding_type_automatic) - detect_coding (&coding, buffer, nread); - if (coding.eol_type == CODING_EOL_AUTOMATIC) - detect_eol (&coding, buffer, nread); - if (lseek (fd, 0, 0) < 0) - report_file_error ("Setting file position", - Fcons (filename, Qnil)); - /* If we still haven't found anything other than - "automatic", change to "no conversion" - so that the replace feature will work. */ - if (coding.type == coding_type_automatic) - coding.type = coding_type_no_conversion; - if (coding.eol_type == CODING_EOL_AUTOMATIC) - coding.eol_type = CODING_EOL_LF; - } - } - /* If requested, replace the accessible part of the buffer with the file contents. Avoid replacing text at the 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\ Here we implement this feature in an optimized way for the case where code conversion is NOT needed. The following if-statement handles the case of conversion - in a less optimal way. */ + in a less optimal way. + + If the code conversion is "automatic" then we try using this + method and hope for the best. + But if we discover the need for conversion, we give up on this method + and let the following if-statement handle the replace job. */ if (!NILP (replace) - && ! CODING_REQUIRE_CONVERSION (&coding)) + && (! CODING_REQUIRE_CONVERSION (&coding) + || (coding.type == coding_type_automatic + && ! CODING_REQUIRE_TEXT_CONVERSION (&coding)) + || (coding.eol_type == CODING_EOL_AUTOMATIC + && ! CODING_REQUIRE_EOL_CONVERSION (&coding)))) { int same_at_start = BEGV; int same_at_end = ZV; int overlap; /* There is still a possibility we will find the need to do code conversion. If that happens, we set this variable to 1 to - give up on the REPLACE feature. */ + give up on handling REPLACE in the optimized way. */ int giveup_match_end = 0; if (XINT (beg) != 0) @@ -3215,6 +3194,26 @@ This does code conversion according to the value of\n\ else if (nread == 0) break; + if (coding.type == coding_type_automatic) + detect_coding (&coding, buffer, nread); + if (CODING_REQUIRE_TEXT_CONVERSION (&coding)) + /* We found that the file should be decoded somehow. + Let's give up here. */ + { + giveup_match_end = 1; + break; + } + + if (coding.eol_type == CODING_EOL_AUTOMATIC) + detect_eol (&coding, buffer, nread); + if (CODING_REQUIRE_EOL_CONVERSION (&coding)) + /* We found that the format of eol should be decoded. + Let's give up here. */ + { + giveup_match_end = 1; + break; + } + bufpos = 0; while (bufpos < nread && same_at_start < ZV && FETCH_BYTE (same_at_start) == buffer[bufpos]) @@ -3272,30 +3271,46 @@ This does code conversion according to the value of\n\ while (bufpos > 0 && same_at_end > same_at_start && FETCH_BYTE (same_at_end - 1) == buffer[bufpos - 1]) same_at_end--, bufpos--; + /* If we found a discrepancy, stop the scan. Otherwise loop around and scan the preceding bufferful. */ if (bufpos != 0) - break; + { + /* If this discrepancy is because of code conversion, + we cannot use this method; giveup and try the other. */ + if (same_at_end > same_at_start + && FETCH_BYTE (same_at_end - 1) >= 0200 + && ! NILP (current_buffer->enable_multibyte_characters)) + giveup_match_end = 1; + break; + } } immediate_quit = 0; - /* Don't try to reuse the same piece of text twice. */ - overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV); - if (overlap > 0) - same_at_end += overlap; + if (! giveup_match_end) + { + /* We win! We can handle REPLACE the optimized way. */ - /* Arrange to read only the nonmatching middle part of the file. */ - XSETFASTINT (beg, XINT (beg) + (same_at_start - BEGV)); - XSETFASTINT (end, XINT (end) - (ZV - same_at_end)); + /* Don't try to reuse the same piece of text twice. */ + overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV); + if (overlap > 0) + same_at_end += overlap; - del_range_1 (same_at_start, same_at_end, 0); - /* Insert from the file at the proper position. */ - SET_PT (same_at_start); + /* Arrange to read only the nonmatching middle part of the file. */ + XSETFASTINT (beg, XINT (beg) + (same_at_start - BEGV)); + XSETFASTINT (end, XINT (end) - (ZV - same_at_end)); - /* If display currently starts at beginning of line, - keep it that way. */ - if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) - XWINDOW (selected_window)->start_at_line_beg = Fbolp (); + del_range_1 (same_at_start, same_at_end, 0); + /* Insert from the file at the proper position. */ + SET_PT (same_at_start); + + /* If display currently starts at beginning of line, + keep it that way. */ + if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) + XWINDOW (selected_window)->start_at_line_beg = Fbolp (); + + replace_handled = 1; + } } /* If requested, replace the accessible part of the buffer @@ -3307,7 +3322,7 @@ This does code conversion according to the value of\n\ is needed, in a simple way that needs a lot of memory. The preceding if-statement handles the case of no conversion in a more optimized way. */ - if (!NILP (replace) && CODING_REQUIRE_CONVERSION (&coding)) + if (!NILP (replace) && ! replace_handled) { int same_at_start = BEGV; int same_at_end = ZV; @@ -3320,6 +3335,13 @@ This does code conversion according to the value of\n\ /* First read the whole file, performing code conversion into CONVERSION_BUFFER. */ + if (lseek (fd, XINT (beg), 0) < 0) + { + free (conversion_buffer); + report_file_error ("Setting file position", + Fcons (filename, Qnil)); + } + total = st.st_size; /* Total bytes in the file. */ how_much = 0; /* Bytes read from file so far. */ inserted = 0; /* Bytes put into CONVERSION_BUFFER so far. */ @@ -3430,23 +3452,23 @@ This does code conversion according to the value of\n\ if (overlap > 0) same_at_end += overlap; + /* If display currently starts at beginning of line, + keep it that way. */ + if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) + XWINDOW (selected_window)->start_at_line_beg = Fbolp (); + /* Replace the chars that we need to replace, and update INSERTED to equal the number of bytes we are taking from the file. */ inserted -= (Z - same_at_end) + (same_at_start - BEG); move_gap (same_at_start); del_range_1 (same_at_start, same_at_end, 0); - make_gap (inserted); insert (conversion_buffer + same_at_start - BEG, inserted); free (conversion_buffer); close (fd); specpdl_ptr--; - /* If display currently starts at beginning of line, - keep it that way. */ - if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer) - XWINDOW (selected_window)->start_at_line_beg = Fbolp (); goto handled; } -- 2.39.2