changeset 5975:c766d816b07e

(Finsert_file_contents): New arg REPLACE. New feature to replace buffer contents with file contents.
author Richard M. Stallman <rms@gnu.org>
date Thu, 17 Feb 1994 08:38:34 +0000
parents bee9069f17e3
children 77cdcc5fda2d
files src/fileio.c
diffstat 1 files changed, 97 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/fileio.c	Thu Feb 17 08:19:58 1994 +0000
+++ b/src/fileio.c	Thu Feb 17 08:38:34 1994 +0000
@@ -2485,7 +2485,7 @@
 #endif
 
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
-  1, 4, 0,
+  1, 5, 0,
   "Insert contents of file FILENAME after point.\n\
 Returns list of absolute file name and length of data inserted.\n\
 If second argument VISIT is non-nil, the buffer's visited filename\n\
@@ -2494,9 +2494,14 @@
 before the error is signaled.\n\n\
 The optional third and fourth arguments BEG and END\n\
 specify what portion of the file to insert.\n\
-If VISIT is non-nil, BEG and END must be nil.")
-  (filename, visit, beg, end)
-     Lisp_Object filename, visit, beg, end;
+If VISIT is non-nil, BEG and END must be nil.\n\
+If optional fifth argument REPLACE is non-nil,\n\
+it means replace the current buffer contents (in the accessible portion)\n\
+with the file contents.  This is better than simply deleting and inserting\n\
+the whole thing because (1) it preserves some marker positions\n\
+and (2) it puts less data in the undo list.")
+  (filename, visit, beg, end, replace)
+     Lisp_Object filename, visit, beg, end, replace;
 {
   struct stat st;
   register int fd;
@@ -2523,7 +2528,8 @@
   handler = Ffind_file_name_handler (filename);
   if (!NILP (handler))
     {
-      val = call5 (handler, Qinsert_file_contents, filename, visit, beg, end);
+      val = call6 (handler, Qinsert_file_contents, filename,
+		   visit, beg, end, replace);
       goto handled;
     }
 
@@ -2579,6 +2585,92 @@
 	error ("maximum buffer size exceeded");
     }
 
+  /* 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;
+     that preserves markers pointing to the unchanged parts.  */
+  if (!NILP (replace))
+    {
+      char buffer[1 << 14];
+      int same_at_start = BEGV;
+      int same_at_end = ZV;
+      immediate_quit = 1;
+      QUIT;
+      /* Count how many chars at the start of the file
+	 match the text at the beginning of the buffer.  */
+      while (1)
+	{
+	  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)
+	    break;
+	  bufpos = 0;
+	  while (bufpos < nread && same_at_start < ZV
+		 && FETCH_CHAR (same_at_start) == buffer[bufpos])
+	    same_at_start++, bufpos++;
+	  /* If we found a discrepancy, stop the scan.
+	     Otherwise loop around and scan the next bufferfull.  */
+	  if (bufpos != nread)
+	    break;
+	}
+      immediate_quit = 0;
+      /* If the file matches the buffer completely,
+	 there's no need to replace anything.  */
+      if (same_at_start == ZV)
+	{
+	  close (fd);
+	  goto handled;
+	}
+      immediate_quit = 1;
+      QUIT;
+      /* Count how many chars at the end of the file
+	 match the text at the end of the buffer.  */
+      while (1)
+	{
+	  int total_read, nread, bufpos, curpos, trial;
+
+	  /* At what file position are we now scanning?  */
+	  curpos = st.st_size - (ZV - same_at_end);
+	  /* How much can we scan in the next step?  */
+	  trial = min (curpos, sizeof buffer);
+	  if (lseek (fd, curpos - trial, 0) < 0)
+	    report_file_error ("Setting file position",
+			       Fcons (filename, Qnil));
+
+	  total_read = 0;
+	  while (total_read < trial)
+	    {
+	      nread = read (fd, buffer + total_read, trial - total_read);
+	      if (nread <= 0)
+		error ("IO error reading %s: %s",
+		       XSTRING (filename)->data, strerror (errno));
+	      total_read += nread;
+	    }
+	  /* Scan this bufferfull from the end, comparing with
+	     the Emacs buffer.  */
+	  bufpos = total_read;
+	  /* Compare with same_at_start to avoid counting some buffer text
+	     as matching both at the file's beginning and at the end.  */
+	  while (bufpos > 0 && same_at_end > same_at_start
+		 && FETCH_CHAR (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 bufferfull.  */
+	  if (bufpos != 0)
+	    break;
+	}
+      immediate_quit = 0;
+      /* Arrange to read only the nonmatching middle part of the file.  */
+      XFASTINT (beg) = same_at_start - BEGV;
+      XFASTINT (end) = st.st_size - (ZV - same_at_end);
+      /* Delete the nonmatching middle part of the buffer.  */
+      Fdelete_region (make_number (same_at_start), make_number (same_at_end));
+    }
+
   total = XINT (end) - XINT (beg);
 
   {