]> code.delx.au - gnu-emacs/blobdiff - src/fileio.c
Merge from emacs--rel--22
[gnu-emacs] / src / fileio.c
index cc6c7c2d3a73654473c5c314b3460b0369bef40c..a63ac6dd74860daab56dcdea317d077d7d30c538 100644 (file)
@@ -21,6 +21,7 @@ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
+#include <limits.h>
 
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
@@ -67,17 +68,15 @@ extern int errno;
 #endif
 #endif
 
-#ifdef APOLLO
-#include <sys/time.h>
-#endif
-
 #include "lisp.h"
 #include "intervals.h"
 #include "buffer.h"
-#include "charset.h"
+#include "character.h"
 #include "coding.h"
 #include "window.h"
 #include "blockinput.h"
+#include "frame.h"
+#include "dispextern.h"
 
 #ifdef WINDOWSNT
 #define NOMINMAX 1
@@ -274,9 +273,12 @@ report_file_error (string, data)
 {
   Lisp_Object errstring;
   int errorno = errno;
+  char *str;
 
   synchronize_system_messages_locale ();
-  errstring = code_convert_string_norecord (build_string (strerror (errorno)),
+  str = strerror (errorno);
+  errstring = code_convert_string_norecord (make_unibyte_string (str,
+                                                                strlen (str)),
                                            Vlocale_coding_system, 0);
 
   while (1)
@@ -314,6 +316,7 @@ restore_point_unwind (location)
   Fset_marker (location, Qnil, Qnil);
   return Qnil;
 }
+
 \f
 Lisp_Object Qexpand_file_name;
 Lisp_Object Qsubstitute_in_file_name;
@@ -532,6 +535,8 @@ A `directly usable' directory name is one that may be used without the
 intervention of any file handler.
 If FILENAME is a directly usable file itself, return
 \(file-name-directory FILENAME).
+If FILENAME refers to a file which is not accessible from a local process,
+then this should return nil.
 The `call-process' and `start-process' functions use this function to
 get a current directory to run processes in.  */)
      (filename)
@@ -810,12 +815,6 @@ directory_file_name (src, dst)
   /* Process as Unix format: just remove any final slash.
      But leave "/" unchanged; do not change it to "".  */
   strcpy (dst, src);
-#ifdef APOLLO
-  /* Handle // as root for apollo's.  */
-  if ((slen > 2 && dst[slen - 1] == '/')
-      || (slen > 1 && dst[0] != '/' && dst[slen - 1] == '/'))
-    dst[slen - 1] = 0;
-#else
   if (slen > 1
       && IS_DIRECTORY_SEP (dst[slen - 1])
 #ifdef DOS_NT
@@ -823,7 +822,6 @@ directory_file_name (src, dst)
 #endif
       )
     dst[slen - 1] = 0;
-#endif
 #ifdef DOS_NT
   CORRECT_DIR_SEPS (dst);
 #endif
@@ -1044,11 +1042,14 @@ See also the function `substitute-in-file-name'.  */)
      (name, default_directory)
      Lisp_Object name, default_directory;
 {
-  unsigned char *nm;
+  /* These point to SDATA and need to be careful with string-relocation
+     during GC (via DECODE_FILE).  */
+  unsigned char *nm, *newdir;
+  int nm_in_name;
+  /* This should only point to alloca'd data.  */
+  unsigned char *target;
 
-  register unsigned char *newdir, *p, *o;
   int tlen;
-  unsigned char *target;
   struct passwd *pw;
 #ifdef VMS
   unsigned char * colon = 0;
@@ -1066,6 +1067,7 @@ See also the function `substitute-in-file-name'.  */)
   int length;
   Lisp_Object handler, result;
   int multibyte;
+  Lisp_Object hdir;
 
   CHECK_STRING (name);
 
@@ -1104,51 +1106,66 @@ See also the function `substitute-in-file-name'.  */)
        return call3 (handler, Qexpand_file_name, name, default_directory);
     }
 
-  o = SDATA (default_directory);
-
-  /* Make sure DEFAULT_DIRECTORY is properly expanded.
-     It would be better to do this down below where we actually use
-     default_directory.  Unfortunately, calling Fexpand_file_name recursively
-     could invoke GC, and the strings might be relocated.  This would
-     be annoying because we have pointers into strings lying around
-     that would need adjusting, and people would add new pointers to
-     the code and forget to adjust them, resulting in intermittent bugs.
-     Putting this call here avoids all that crud.
-
-     The EQ test avoids infinite recursion.  */
-  if (! NILP (default_directory) && !EQ (default_directory, name)
-      /* Save time in some common cases - as long as default_directory
-        is not relative, it can be canonicalized with name below (if it
-        is needed at all) without requiring it to be expanded now.  */
+  {
+    unsigned char *o = SDATA (default_directory);
+
+    /* Make sure DEFAULT_DIRECTORY is properly expanded.
+       It would be better to do this down below where we actually use
+       default_directory.  Unfortunately, calling Fexpand_file_name recursively
+       could invoke GC, and the strings might be relocated.  This would
+       be annoying because we have pointers into strings lying around
+       that would need adjusting, and people would add new pointers to
+       the code and forget to adjust them, resulting in intermittent bugs.
+       Putting this call here avoids all that crud.
+
+       The EQ test avoids infinite recursion.  */
+    if (! NILP (default_directory) && !EQ (default_directory, name)
+       /* Save time in some common cases - as long as default_directory
+          is not relative, it can be canonicalized with name below (if it
+          is needed at all) without requiring it to be expanded now.  */
 #ifdef DOS_NT
-      /* Detect MSDOS file names with drive specifiers.  */
-      && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2]))
+       /* Detect MSDOS file names with drive specifiers.  */
+       && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1])
+             && IS_DIRECTORY_SEP (o[2]))
 #ifdef WINDOWSNT
-      /* Detect Windows file names in UNC format.  */
-      && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1]))
+       /* Detect Windows file names in UNC format.  */
+       && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1]))
 #endif
 #else /* not DOS_NT */
       /* Detect Unix absolute file names (/... alone is not absolute on
         DOS or Windows).  */
-      && ! (IS_DIRECTORY_SEP (o[0]))
+       && ! (IS_DIRECTORY_SEP (o[0]))
 #endif /* not DOS_NT */
-      )
-    {
-      struct gcpro gcpro1;
+       )
+      {
+       struct gcpro gcpro1;
 
-      GCPRO1 (name);
-      default_directory = Fexpand_file_name (default_directory, Qnil);
-      UNGCPRO;
+       GCPRO1 (name);
+       default_directory = Fexpand_file_name (default_directory, Qnil);
+       UNGCPRO;
+      }
+  }
+  name = FILE_SYSTEM_CASE (name);
+  multibyte = STRING_MULTIBYTE (name);
+  if (multibyte != STRING_MULTIBYTE (default_directory))
+    {
+      if (multibyte)
+       default_directory = string_to_multibyte (default_directory);
+      else
+       {
+         name = string_to_multibyte (name);
+         multibyte = 1;
+       }
     }
 
-  name = FILE_SYSTEM_CASE (name);
   nm = SDATA (name);
-  multibyte = STRING_MULTIBYTE (name);
+  nm_in_name = 1;
 
 #ifdef DOS_NT
   /* We will force directory separators to be either all \ or /, so make
      a local copy to modify, even if there ends up being no change. */
   nm = strcpy (alloca (strlen (nm) + 1), nm);
+  nm_in_name = 0;
 
   /* Note if special escape prefix is present, but remove for now.  */
   if (nm[0] == '/' && nm[1] == ':')
@@ -1172,16 +1189,14 @@ See also the function `substitute-in-file-name'.  */)
      "//somedir".  */
   if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
     nm++;
-#endif /* WINDOWSNT */
-#endif /* DOS_NT */
 
-#ifdef WINDOWSNT
   /* Discard any previous drive specifier if nm is now in UNC format. */
   if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
     {
       drive = 0;
     }
-#endif
+#endif /* WINDOWSNT */
+#endif /* DOS_NT */
 
   /* If nm is absolute, look for `/./' or `/../' or `//''sequences; if
      none are found, we can probably return right away.  We will avoid
@@ -1206,8 +1221,8 @@ See also the function `substitute-in-file-name'.  */)
         non-zero value, that means we've discovered that we can't do
         that cool trick.  */
       int lose = 0;
+      unsigned char *p = nm;
 
-      p = nm;
       while (*p)
        {
          /* Since we know the name is absolute, we can assume that each
@@ -1309,6 +1324,7 @@ See also the function `substitute-in-file-name'.  */)
          if (index (nm, '/'))
            {
              nm = sys_translate_unix (nm);
+             nm_in_name = 0;
              return make_specified_string (nm, -1, strlen (nm), multibyte);
            }
 #endif /* VMS */
@@ -1369,9 +1385,24 @@ See also the function `substitute-in-file-name'.  */)
 #endif /* VMS */
          || nm[1] == 0)        /* ~ by itself */
        {
+         Lisp_Object tem;
+
          if (!(newdir = (unsigned char *) egetenv ("HOME")))
            newdir = (unsigned char *) "";
          nm++;
+         /* egetenv may return a unibyte string, which will bite us since
+            we expect the directory to be multibyte.  */
+         tem = build_string (newdir);
+         if (!STRING_MULTIBYTE (tem))
+           {
+             /* FIXME: DECODE_FILE may GC, which may move SDATA(name),
+                after which `nm' won't point to the right place any more.  */
+             int offset = nm - SDATA (name);
+             hdir = DECODE_FILE (tem);
+             newdir = SDATA (hdir);
+             if (nm_in_name)
+             nm = SDATA (name) + offset;
+           }
 #ifdef DOS_NT
          collapse_newdir = 0;
 #endif
@@ -1381,12 +1412,13 @@ See also the function `substitute-in-file-name'.  */)
        }
       else                     /* ~user/filename */
        {
+         unsigned char *o, *p;
          for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)
 #ifdef VMS
                              && *p != ':'
 #endif /* VMS */
                              ); p++);
-         o = (unsigned char *) alloca (p - nm + 1);
+         o = alloca (p - nm + 1);
          bcopy ((char *) nm, o, p - nm);
          o [p - nm] = 0;
 
@@ -1452,7 +1484,6 @@ See also the function `substitute-in-file-name'.  */)
       && !newdir)
     {
       newdir = SDATA (default_directory);
-      multibyte |= STRING_MULTIBYTE (default_directory);
 #ifdef DOS_NT
       /* Note if special escape prefix is present, but remove for now.  */
       if (newdir[0] == '/' && newdir[1] == ':')
@@ -1519,6 +1550,7 @@ See also the function `substitute-in-file-name'.  */)
 #ifdef WINDOWSNT
          if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]))
            {
+             unsigned char *p;
              newdir = strcpy (alloca (strlen (newdir) + 1), newdir);
              p = newdir + 2;
              while (*p && !IS_DIRECTORY_SEP (*p)) p++;
@@ -1599,120 +1631,122 @@ See also the function `substitute-in-file-name'.  */)
   /* Now canonicalize by removing `//', `/.' and `/foo/..' if they
      appear.  */
 
-  p = target;
-  o = target;
+  {
+    unsigned char *p = target;
+    unsigned char *o = target;
 
-  while (*p)
-    {
+    while (*p)
+      {
 #ifdef VMS
-      if (*p != ']' && *p != '>' && *p != '-')
-       {
-         if (*p == '\\')
-           p++;
-         *o++ = *p++;
-       }
-      else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
-       /* brackets are offset from each other by 2 */
-       {
-         p += 2;
-         if (*p != '.' && *p != '-' && o[-1] != '.')
-           /* convert [foo][bar] to [bar] */
-           while (o[-1] != '[' && o[-1] != '<')
-             o--;
-         else if (*p == '-' && *o != '.')
-           *--p = '.';
-       }
-      else if (p[0] == '-' && o[-1] == '.'
-              && (p[1] == '.' || p[1] == ']' || p[1] == '>'))
-       /* flush .foo.- ; leave - if stopped by '[' or '<' */
-       {
-         do
-           o--;
-         while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
-         if (p[1] == '.')      /* foo.-.bar ==> bar.  */
+       if (*p != ']' && *p != '>' && *p != '-')
+         {
+           if (*p == '\\')
+             p++;
+           *o++ = *p++;
+         }
+       else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
+         /* brackets are offset from each other by 2 */
+         {
            p += 2;
-         else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
-           p++, o--;
-         /* else [foo.-] ==> [-] */
-       }
-      else
-       {
+           if (*p != '.' && *p != '-' && o[-1] != '.')
+             /* convert [foo][bar] to [bar] */
+             while (o[-1] != '[' && o[-1] != '<')
+               o--;
+           else if (*p == '-' && *o != '.')
+             *--p = '.';
+         }
+       else if (p[0] == '-' && o[-1] == '.'
+                && (p[1] == '.' || p[1] == ']' || p[1] == '>'))
+         /* flush .foo.- ; leave - if stopped by '[' or '<' */
+         {
+           do
+             o--;
+           while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
+           if (p[1] == '.')      /* foo.-.bar ==> bar.  */
+             p += 2;
+           else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
+             p++, o--;
+           /* else [foo.-] ==> [-] */
+         }
+       else
+         {
 #ifdef NO_HYPHENS_IN_FILENAMES
-         if (*p == '-'
-             && o[-1] != '[' && o[-1] != '<' && o[-1] != '.'
-             && p[1] != ']' && p[1] != '>' && p[1] != '.')
-           *p = '_';
+           if (*p == '-'
+               && o[-1] != '[' && o[-1] != '<' && o[-1] != '.'
+               && p[1] != ']' && p[1] != '>' && p[1] != '.')
+             *p = '_';
 #endif /* NO_HYPHENS_IN_FILENAMES */
-         *o++ = *p++;
-       }
+           *o++ = *p++;
+         }
 #else /* not VMS */
-      if (!IS_DIRECTORY_SEP (*p))
-       {
-         *o++ = *p++;
-       }
-      else if (p[1] == '.'
-              && (IS_DIRECTORY_SEP (p[2])
-                  || p[2] == 0))
-       {
-         /* If "/." is the entire filename, keep the "/".  Otherwise,
-            just delete the whole "/.".  */
-         if (o == target && p[2] == '\0')
-           *o++ = *p;
-         p += 2;
-       }
-      else if (p[1] == '.' && p[2] == '.'
-              /* `/../' is the "superroot" on certain file systems.
-                 Turned off on DOS_NT systems because they have no
-                 "superroot" and because this causes us to produce
-                 file names like "d:/../foo" which fail file-related
-                 functions of the underlying OS.  (To reproduce, try a
-                 long series of "../../" in default_directory, longer
-                 than the number of levels from the root.)  */
+       if (!IS_DIRECTORY_SEP (*p))
+         {
+           *o++ = *p++;
+         }
+       else if (p[1] == '.'
+                && (IS_DIRECTORY_SEP (p[2])
+                    || p[2] == 0))
+         {
+           /* If "/." is the entire filename, keep the "/".  Otherwise,
+              just delete the whole "/.".  */
+           if (o == target && p[2] == '\0')
+             *o++ = *p;
+           p += 2;
+         }
+       else if (p[1] == '.' && p[2] == '.'
+                /* `/../' is the "superroot" on certain file systems.
+                   Turned off on DOS_NT systems because they have no
+                   "superroot" and because this causes us to produce
+                   file names like "d:/../foo" which fail file-related
+                   functions of the underlying OS.  (To reproduce, try a
+                   long series of "../../" in default_directory, longer
+                   than the number of levels from the root.)  */
 #ifndef DOS_NT
-              && o != target
+                && o != target
 #endif
-              && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
-       {
-         while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
-           ;
-         /* Keep initial / only if this is the whole name.  */
-         if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
-           ++o;
-         p += 3;
-       }
-      else if (p > target && IS_DIRECTORY_SEP (p[1]))
-       /* Collapse multiple `/' in a row.  */
-       p++;
-      else
-       {
-         *o++ = *p++;
-       }
+                && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
+         {
+           while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
+             ;
+           /* Keep initial / only if this is the whole name.  */
+           if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
+             ++o;
+           p += 3;
+         }
+       else if (p > target && IS_DIRECTORY_SEP (p[1]))
+         /* Collapse multiple `/' in a row.  */
+         p++;
+       else
+         {
+           *o++ = *p++;
+         }
 #endif /* not VMS */
-    }
+      }
 
 #ifdef DOS_NT
-  /* At last, set drive name. */
+    /* At last, set drive name. */
 #ifdef WINDOWSNT
-  /* Except for network file name.  */
-  if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1])))
+    /* Except for network file name.  */
+    if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1])))
 #endif /* WINDOWSNT */
-    {
-      if (!drive) abort ();
-      target -= 2;
-      target[0] = DRIVE_LETTER (drive);
-      target[1] = ':';
-    }
-  /* Reinsert the escape prefix if required.  */
-  if (is_escaped)
-    {
-      target -= 2;
-      target[0] = '/';
-      target[1] = ':';
-    }
-  CORRECT_DIR_SEPS (target);
+      {
+       if (!drive) abort ();
+       target -= 2;
+       target[0] = DRIVE_LETTER (drive);
+       target[1] = ':';
+      }
+    /* Reinsert the escape prefix if required.  */
+    if (is_escaped)
+      {
+       target -= 2;
+       target[0] = '/';
+       target[1] = ':';
+      }
+    CORRECT_DIR_SEPS (target);
 #endif /* DOS_NT */
 
-  result = make_specified_string (target, -1, o - target, multibyte);
+    result = make_specified_string (target, -1, o - target, multibyte);
+  }
 
   /* Again look to see if the file name has special constructs in it
      and perhaps call the corresponding file handler.  This is needed
@@ -1788,10 +1822,6 @@ See also the function `substitute-in-file-name'.")
       while (*p)
        {
          if (p[0] == '/' && p[1] == '/'
-#ifdef APOLLO
-             /* // at start of filename is meaningful on Apollo system.  */
-             && nm != p
-#endif /* APOLLO */
              )
            nm = p + 1;
          if (p[0] == '/' && p[1] == '~')
@@ -2023,10 +2053,6 @@ See also the function `substitute-in-file-name'.")
          *o++ = *p++;
        }
       else if (!strncmp (p, "//", 2)
-#ifdef APOLLO
-              /* // at start of filename is meaningful in Apollo system.  */
-              && o != target
-#endif /* APOLLO */
               )
        {
          o = target;
@@ -2042,11 +2068,6 @@ See also the function `substitute-in-file-name'.")
        {
          while (o != target && *--o != '/')
            ;
-#ifdef APOLLO
-         if (o == target + 1 && o[-1] == '/' && o[0] == '/')
-           ++o;
-         else
-#endif /* APOLLO */
          if (o == target && *o == '/')
            ++o;
          p += 3;
@@ -2097,11 +2118,11 @@ search_embedded_absfilename (nm, endp)
 #endif /* VMS */
           || IS_DIRECTORY_SEP (p[-1]))
          && file_name_absolute_p (p)
-#if defined (APOLLO) || defined (WINDOWSNT) || defined(CYGWIN)
+#if defined (WINDOWSNT) || defined(CYGWIN)
          /* // at start of file name is meaningful in Apollo,
             WindowsNT and Cygwin systems.  */
          && !(IS_DIRECTORY_SEP (p[0]) && p - 1 == nm)
-#endif /* not (APOLLO || WINDOWSNT || CYGWIN) */
+#endif /* not (WINDOWSNT || CYGWIN) */
              )
        {
          for (s = p; *s && (!IS_DIRECTORY_SEP (*s)
@@ -2294,7 +2315,8 @@ duplicates what `expand-file-name' does.  */)
               convert what we substitute into multibyte.  */
            while (*o)
              {
-               int c = unibyte_char_to_multibyte (*o++);
+               int c = *o++;
+               c = unibyte_char_to_multibyte (c);
                x += CHAR_STRING (c, x);
              }
          }
@@ -2466,8 +2488,8 @@ uid and gid of FILE to NEWNAME.  */)
   if (NILP (handler))
     handler = Ffind_file_name_handler (newname, Qcopy_file);
   if (!NILP (handler))
-    RETURN_UNGCPRO (call5 (handler, Qcopy_file, file, newname,
-                          ok_if_already_exists, keep_time));
+    RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname,
+                          ok_if_already_exists, keep_time, preserve_uid_gid));
 
   encoded_file = ENCODE_FILE (file);
   encoded_newname = ENCODE_FILE (newname);
@@ -3441,7 +3463,9 @@ Return nil, if file does not exist or is not accessible.  */)
   return make_number (st.st_mode & 07777);
 }
 
-DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
+DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2,
+       "(let ((file (read-file-name \"File: \")))                      \
+         (list file (read-file-modes nil file)))",
        doc: /* Set mode bits of file named FILENAME to MODE (an integer).
 Only the 12 low bits of MODE are used.  */)
   (filename, mode)
@@ -3698,38 +3722,37 @@ DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
        1, 5, 0,
        doc: /* Insert contents of file FILENAME after point.
 Returns list of absolute file name and number of characters inserted.
-If second argument VISIT is non-nil, the buffer's visited filename
-and last save file modtime are set, and it is marked unmodified.
-If visiting and the file does not exist, visiting is completed
-before the error is signaled.
-The optional third and fourth arguments BEG and END
-specify what portion of the file to insert.
-These arguments count bytes in the file, not characters in the buffer.
-If VISIT is non-nil, BEG and END must be nil.
-
-If optional fifth argument REPLACE is non-nil,
-it means replace the current buffer contents (in the accessible portion)
-with the file contents.  This is better than simply deleting and inserting
-the whole thing because (1) it preserves some marker positions
-and (2) it puts less data in the undo list.
-When REPLACE is non-nil, the value is the number of characters actually read,
-which is often less than the number of characters to be read.
-
-This does code conversion according to the value of
-`coding-system-for-read' or `file-coding-system-alist',
-and sets the variable `last-coding-system-used' to the coding system
-actually used.  */)
+If second argument VISIT is non-nil, the buffer's visited filename and
+last save file modtime are set, and it is marked unmodified.  If
+visiting and the file does not exist, visiting is completed before the
+error is signaled.
+
+The optional third and fourth arguments BEG and END specify what portion
+of the file to insert.  These arguments count bytes in the file, not
+characters in the buffer.  If VISIT is non-nil, BEG and END must be nil.
+
+If optional fifth argument REPLACE is non-nil, replace the current
+buffer contents (in the accessible portion) with the file contents.
+This is better than simply deleting and inserting the whole thing
+because (1) it preserves some marker positions and (2) it puts less data
+in the undo list.  When REPLACE is non-nil, the second return value is
+the number of characters that replace previous buffer contents.
+
+This function does code conversion according to the value of
+`coding-system-for-read' or `file-coding-system-alist', and sets the
+variable `last-coding-system-used' to the coding system actually used.  */)
      (filename, visit, beg, end, replace)
      Lisp_Object filename, visit, beg, end, replace;
 {
   struct stat st;
   register int fd;
   int inserted = 0;
+  int nochange = 0;
   register int how_much;
   register int unprocessed;
   int count = SPECPDL_INDEX ();
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-  Lisp_Object handler, val, insval, orig_filename;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+  Lisp_Object handler, val, insval, orig_filename, old_undo;
   Lisp_Object p;
   int total = 0;
   int not_regular = 0;
@@ -3738,7 +3761,7 @@ actually used.  */)
   unsigned char buffer[1 << 14];
   int replace_handled = 0;
   int set_coding_system = 0;
-  int coding_system_decided = 0;
+  Lisp_Object coding_system;
   int read_quit = 0;
   Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark;
   int we_locked_file = 0;
@@ -3752,12 +3775,17 @@ actually used.  */)
   val = Qnil;
   p = Qnil;
   orig_filename = Qnil;
+  old_undo = Qnil;
 
-  GCPRO4 (filename, val, p, orig_filename);
+  GCPRO5 (filename, val, p, orig_filename, old_undo);
 
   CHECK_STRING (filename);
   filename = Fexpand_file_name (filename, Qnil);
 
+  /* The value Qnil means that the coding system is not yet
+     decided.  */
+  coding_system = Qnil;
+
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
   handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
@@ -3786,12 +3814,7 @@ actually used.  */)
   }
   if (total < 0)
 #else
-#ifndef APOLLO
   if (stat (SDATA (filename), &st) < 0)
-#else
-  if ((fd = emacs_open (SDATA (filename), O_RDONLY, 0)) < 0
-      || fstat (fd, &st) < 0)
-#endif /* not APOLLO */
 #endif /* WINDOWSNT */
     {
       if (fd >= 0) emacs_close (fd);
@@ -3868,7 +3891,7 @@ actually used.  */)
             overflow.  The calculations below double the file size
             twice, so check that it can be multiplied by 4 safely.  */
          if (XINT (end) != st.st_size
-             || ((int) st.st_size * 4) / 4 != st.st_size)
+             || st.st_size > INT_MAX / 4)
            error ("Maximum buffer size exceeded");
 
          /* The file size returned from stat may be zero, but data
@@ -3881,27 +3904,18 @@ actually used.  */)
 
   if (EQ (Vcoding_system_for_read, Qauto_save_coding))
     {
-      /* We use emacs-mule for auto saving... */
-      setup_coding_system (Qemacs_mule, &coding);
-      /* ... but with the special flag to indicate to read in a
-        multibyte sequence for eight-bit-control char as is.  */
-      coding.flags = 1;
-      coding.src_multibyte = 0;
-      coding.dst_multibyte
-       = !NILP (current_buffer->enable_multibyte_characters);
-      coding.eol_type = CODING_EOL_LF;
-      coding_system_decided = 1;
+      coding_system = coding_inherit_eol_type (Qutf_8_emacs, Qunix);
+      setup_coding_system (coding_system, &coding);
+      /* Ensure we set Vlast_coding_system_used.  */
+      set_coding_system = 1;
     }
   else if (BEG < Z)
     {
       /* Decide the coding system to use for reading the file now
          because we can't use an optimized method for handling
          `coding:' tag if the current buffer is not empty.  */
-      Lisp_Object val;
-      val = Qnil;
-
       if (!NILP (Vcoding_system_for_read))
-       val = Vcoding_system_for_read;
+       coding_system = Vcoding_system_for_read;
       else
        {
          /* Don't try looking inside a file for a coding system
@@ -3957,8 +3971,8 @@ actually used.  */)
 
                  insert_1_both (read_buf, nread, nread, 0, 0, 0);
                  TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
-                 val = call2 (Vset_auto_coding_function,
-                              filename, make_number (nread));
+                 coding_system = call2 (Vset_auto_coding_function,
+                                        filename, make_number (nread));
                  set_buffer_internal (prev);
 
                  /* Discard the unwind protect for recovering the
@@ -3972,34 +3986,33 @@ actually used.  */)
                }
            }
 
-         if (NILP (val))
+         if (NILP (coding_system))
            {
              /* If we have not yet decided a coding system, check
                  file-coding-system-alist.  */
-             Lisp_Object args[6], coding_systems;
+             Lisp_Object args[6];
 
              args[0] = Qinsert_file_contents, args[1] = orig_filename;
              args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
-             coding_systems = Ffind_operation_coding_system (6, args);
-             if (CONSP (coding_systems))
-               val = XCAR (coding_systems);
+             coding_system = Ffind_operation_coding_system (6, args);
+             if (CONSP (coding_system))
+               coding_system = XCAR (coding_system);
            }
        }
 
-      setup_coding_system (Fcheck_coding_system (val), &coding);
-      /* Ensure we set Vlast_coding_system_used.  */
-      set_coding_system = 1;
+      if (NILP (coding_system))
+       coding_system = Qundecided;
+      else
+       CHECK_CODING_SYSTEM (coding_system);
 
-      if (NILP (current_buffer->enable_multibyte_characters)
-         && ! NILP (val))
+      if (NILP (current_buffer->enable_multibyte_characters))
        /* We must suppress all character code conversion except for
           end-of-line conversion.  */
-       setup_raw_text_coding_system (&coding);
+       coding_system = raw_text_coding_system (coding_system);
 
-      coding.src_multibyte = 0;
-      coding.dst_multibyte
-       = !NILP (current_buffer->enable_multibyte_characters);
-      coding_system_decided = 1;
+      setup_coding_system (coding_system, &coding);
+      /* Ensure we set Vlast_coding_system_used.  */
+      set_coding_system = 1;
     }
 
   /* If requested, replace the accessible part of the buffer
@@ -4018,7 +4031,8 @@ actually used.  */)
      and let the following if-statement handle the replace job.  */
   if (!NILP (replace)
       && BEGV < ZV
-      && !(coding.common_flags & CODING_REQUIRE_DECODING_MASK))
+      && (NILP (coding_system)
+         || ! CODING_REQUIRE_DECODING (&coding)))
     {
       /* same_at_start and same_at_end count bytes,
         because file access counts bytes
@@ -4053,21 +4067,15 @@ actually used.  */)
          else if (nread == 0)
            break;
 
-         if (coding.type == coding_type_undecided)
-           detect_coding (&coding, buffer, nread);
-         if (coding.common_flags & CODING_REQUIRE_DECODING_MASK)
-           /* We found that the file should be decoded somehow.
-               Let's give up here.  */
+         if (CODING_REQUIRE_DETECTION (&coding))
            {
-             giveup_match_end = 1;
-             break;
+             coding_system = detect_coding_system (buffer, nread, nread, 1, 0,
+                                                   coding_system);
+             setup_coding_system (coding_system, &coding);
            }
 
-         if (coding.eol_type == CODING_EOL_UNDECIDED)
-           detect_eol (&coding, buffer, nread);
-         if (coding.eol_type != CODING_EOL_UNDECIDED
-             && coding.eol_type != CODING_EOL_LF)
-           /* We found that the format of eol should be decoded.
+         if (CODING_REQUIRE_DECODING (&coding))
+           /* We found that the file should be decoded somehow.
                Let's give up here.  */
            {
              giveup_match_end = 1;
@@ -4210,126 +4218,113 @@ actually used.  */)
      in a more optimized way.  */
   if (!NILP (replace) && ! replace_handled && BEGV < ZV)
     {
-      int same_at_start = BEGV_BYTE;
-      int same_at_end = ZV_BYTE;
-      int overlap;
-      int bufpos;
-      /* Make sure that the gap is large enough.  */
-      int bufsize = 2 * st.st_size;
-      unsigned char *conversion_buffer = (unsigned char *) xmalloc (bufsize);
+      EMACS_INT same_at_start = BEGV_BYTE;
+      EMACS_INT same_at_end = ZV_BYTE;
+      EMACS_INT same_at_start_charpos;
+      EMACS_INT inserted_chars;
+      EMACS_INT overlap;
+      EMACS_INT bufpos;
+      unsigned char *decoded;
       int temp;
+      int this_count = SPECPDL_INDEX ();
+      int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
+      Lisp_Object conversion_buffer;
+
+      conversion_buffer = code_conversion_save (1, multibyte);
 
       /* First read the whole file, performing code conversion into
         CONVERSION_BUFFER.  */
 
       if (lseek (fd, XINT (beg), 0) < 0)
-       {
-         xfree (conversion_buffer);
-         report_file_error ("Setting file position",
-                            Fcons (orig_filename, Qnil));
-       }
+       report_file_error ("Setting file position",
+                          Fcons (orig_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.  */
       unprocessed = 0;         /* Bytes not processed in previous loop.  */
 
+      GCPRO1 (conversion_buffer);
       while (how_much < total)
        {
+         /* We read one bunch by one (READ_BUF_SIZE bytes) to allow
+            quitting while reading a huge while.  */
          /* try is reserved in some compilers (Microsoft C) */
          int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
-         unsigned char *destination = read_buf + unprocessed;
          int this;
 
          /* Allow quitting out of the actual I/O.  */
          immediate_quit = 1;
          QUIT;
-         this = emacs_read (fd, destination, trytry);
+         this = emacs_read (fd, read_buf + unprocessed, trytry);
          immediate_quit = 0;
 
-         if (this < 0 || this + unprocessed == 0)
+         if (this <= 0)
            {
-             how_much = this;
+             if (this < 0)
+               how_much = this;
              break;
            }
 
          how_much += this;
 
-         if (CODING_MAY_REQUIRE_DECODING (&coding))
-           {
-             int require, result;
-
-             this += unprocessed;
-
-             /* If we are using more space than estimated,
-                make CONVERSION_BUFFER bigger.  */
-             require = decoding_buffer_size (&coding, this);
-             if (inserted + require + 2 * (total - how_much) > bufsize)
-               {
-                 bufsize = inserted + require + 2 * (total - how_much);
-                 conversion_buffer = (unsigned char *) xrealloc (conversion_buffer, bufsize);
-               }
-
-             /* Convert this batch with results in CONVERSION_BUFFER.  */
-             if (how_much >= total)  /* This is the last block.  */
-               coding.mode |= CODING_MODE_LAST_BLOCK;
-             if (coding.composing != COMPOSITION_DISABLED)
-               coding_allocate_composition_data (&coding, BEGV);
-             result = decode_coding (&coding, read_buf,
-                                     conversion_buffer + inserted,
-                                     this, bufsize - inserted);
-
-             /* Save for next iteration whatever we didn't convert.  */
-             unprocessed = this - coding.consumed;
-             bcopy (read_buf + coding.consumed, read_buf, unprocessed);
-             if (!NILP (current_buffer->enable_multibyte_characters))
-               this = coding.produced;
-             else
-               this = str_as_unibyte (conversion_buffer + inserted,
-                                      coding.produced);
-           }
-
-         inserted += this;
+         BUF_TEMP_SET_PT (XBUFFER (conversion_buffer),
+                          BUF_Z (XBUFFER (conversion_buffer)));
+         decode_coding_c_string (&coding, read_buf, unprocessed + this,
+                                 conversion_buffer);
+         unprocessed = coding.carryover_bytes;
+         if (coding.carryover_bytes > 0)
+           bcopy (coding.carryover, read_buf, unprocessed);
        }
+      UNGCPRO;
+      emacs_close (fd);
 
-      /* At this point, INSERTED is how many characters (i.e. bytes)
-        are present in CONVERSION_BUFFER.
-        HOW_MUCH should equal TOTAL,
-        or should be <= 0 if we couldn't read the file.  */
+      /* At this point, HOW_MUCH should equal TOTAL, or should be <= 0
+        if we couldn't read the file.  */
 
       if (how_much < 0)
+       error ("IO error reading %s: %s",
+              SDATA (orig_filename), emacs_strerror (errno));
+
+      if (unprocessed > 0)
        {
-         xfree (conversion_buffer);
-         coding_free_composition_data (&coding);
-         error ("IO error reading %s: %s",
-                SDATA (orig_filename), emacs_strerror (errno));
+         coding.mode |= CODING_MODE_LAST_BLOCK;
+         decode_coding_c_string (&coding, read_buf, unprocessed,
+                                 conversion_buffer);
+         coding.mode &= ~CODING_MODE_LAST_BLOCK;
        }
 
-      /* Compare the beginning of the converted file
-        with the buffer text.  */
+      decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer));
+      inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer))
+                 - BUF_BEG_BYTE (XBUFFER (conversion_buffer)));
+
+      /* Compare the beginning of the converted string with the buffer
+        text.  */
 
       bufpos = 0;
       while (bufpos < inserted && same_at_start < same_at_end
-            && FETCH_BYTE (same_at_start) == conversion_buffer[bufpos])
+            && FETCH_BYTE (same_at_start) == decoded[bufpos])
        same_at_start++, bufpos++;
 
-      /* If the file matches the buffer completely,
+      /* If the file matches the head of buffer completely,
         there's no need to replace anything.  */
 
       if (bufpos == inserted)
        {
-         xfree (conversion_buffer);
-         coding_free_composition_data (&coding);
-         emacs_close (fd);
          specpdl_ptr--;
          /* Truncate the buffer to the size of the file.  */
-         del_range_byte (same_at_start, same_at_end, 0);
+         if (same_at_start == same_at_end)
+           nochange = 1;
+         else
+           del_range_byte (same_at_start, same_at_end, 0);
          inserted = 0;
+
+         unbind_to (this_count, Qnil);
          goto handled;
        }
 
-      /* Extend the start of non-matching text area to multibyte
-        character boundary.  */
+      /* Extend the start of non-matching text area to the previous
+        multibyte character boundary.  */
       if (! NILP (current_buffer->enable_multibyte_characters))
        while (same_at_start > BEGV_BYTE
               && ! CHAR_HEAD_P (FETCH_BYTE (same_at_start)))
@@ -4342,11 +4337,11 @@ actually used.  */)
       /* 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_BYTE (same_at_end - 1) == conversion_buffer[bufpos - 1])
+            && FETCH_BYTE (same_at_end - 1) == decoded[bufpos - 1])
        same_at_end--, bufpos--;
 
-      /* Extend the end of non-matching text area to multibyte
-        character boundary.  */
+      /* Extend the end of non-matching text area to the next
+        multibyte character boundary.  */
       if (! NILP (current_buffer->enable_multibyte_characters))
        while (same_at_end < ZV_BYTE
               && ! CHAR_HEAD_P (FETCH_BYTE (same_at_end)))
@@ -4364,7 +4359,7 @@ actually used.  */)
 
       /* Replace the chars that we need to replace,
         and update INSERTED to equal the number of bytes
-        we are taking from the file.  */
+        we are taking from the decoded string.  */
       inserted -= (ZV_BYTE - same_at_end) + (same_at_start - BEGV_BYTE);
 
       if (same_at_end != same_at_start)
@@ -4379,20 +4374,27 @@ actually used.  */)
        }
       /* Insert from the file at the proper position.  */
       SET_PT_BOTH (temp, same_at_start);
-      insert_1 (conversion_buffer + same_at_start - BEGV_BYTE, inserted,
-               0, 0, 0);
-      if (coding.cmp_data && coding.cmp_data->used)
-       coding_restore_composition (&coding, Fcurrent_buffer ());
-      coding_free_composition_data (&coding);
-
+      same_at_start_charpos
+       = buf_bytepos_to_charpos (XBUFFER (conversion_buffer),
+                                 same_at_start - BEGV_BYTE
+                                 + BUF_BEG_BYTE (XBUFFER (conversion_buffer)));
+      inserted_chars
+       = (buf_bytepos_to_charpos (XBUFFER (conversion_buffer),
+                                  same_at_start + inserted - BEGV_BYTE
+                                 + BUF_BEG_BYTE (XBUFFER (conversion_buffer)))
+          - same_at_start_charpos);
+      /* This binding is to avoid ask-user-about-supersession-threat
+        being called in insert_from_buffer (via in
+        prepare_to_modify_buffer).  */
+      specbind (intern ("buffer-file-name"), Qnil);
+      insert_from_buffer (XBUFFER (conversion_buffer),
+                         same_at_start_charpos, inserted_chars, 0);
       /* Set `inserted' to the number of inserted characters.  */
       inserted = PT - temp;
       /* Set point before the inserted characters.  */
       SET_PT_BOTH (temp, same_at_start);
 
-      xfree (conversion_buffer);
-      emacs_close (fd);
-      specpdl_ptr--;
+      unbind_to (this_count, Qnil);
 
       goto handled;
     }
@@ -4445,7 +4447,7 @@ actually used.  */)
   inserted = 0;
 
   /* Here, we don't do code conversion in the loop.  It is done by
-     code_convert_region after all data are read into the buffer.  */
+     decode_coding_gap after all data are read into the buffer.  */
   {
     int gap_size = GAP_SIZE;
 
@@ -4550,26 +4552,23 @@ actually used.  */)
 
  notfound:
 
-  if (! coding_system_decided)
+  if (NILP (coding_system))
     {
       /* The coding system is not yet decided.  Decide it by an
         optimized method for handling `coding:' tag.
 
         Note that we can get here only if the buffer was empty
         before the insertion.  */
-      Lisp_Object val;
-      val = Qnil;
 
       if (!NILP (Vcoding_system_for_read))
-       val = Vcoding_system_for_read;
+       coding_system = Vcoding_system_for_read;
       else
        {
          /* Since we are sure that the current buffer was empty
             before the insertion, we can toggle
             enable-multibyte-characters directly here without taking
-            care of marker adjustment and byte combining problem.  By
-            this way, we can run Lisp program safely before decoding
-            the inserted text.  */
+            care of marker adjustment.  By this way, we can run Lisp
+            program safely before decoding the inserted text.  */
          Lisp_Object unwind_data;
          int count = SPECPDL_INDEX ();
 
@@ -4582,83 +4581,69 @@ actually used.  */)
 
          if (inserted > 0 && ! NILP (Vset_auto_coding_function))
            {
-             val = call2 (Vset_auto_coding_function,
-                          filename, make_number (inserted));
+             coding_system = call2 (Vset_auto_coding_function,
+                                    filename, make_number (inserted));
            }
 
-         if (NILP (val))
+         if (NILP (coding_system))
            {
              /* If the coding system is not yet decided, check
                 file-coding-system-alist.  */
-             Lisp_Object args[6], coding_systems;
+             Lisp_Object args[6];
 
              args[0] = Qinsert_file_contents, args[1] = orig_filename;
              args[2] = visit, args[3] = beg, args[4] = end, args[5] = Qnil;
-             coding_systems = Ffind_operation_coding_system (6, args);
-             if (CONSP (coding_systems))
-               val = XCAR (coding_systems);
+             coding_system = Ffind_operation_coding_system (6, args);
+             if (CONSP (coding_system))
+               coding_system = XCAR (coding_system);
            }
          unbind_to (count, Qnil);
          inserted = Z_BYTE - BEG_BYTE;
        }
 
-      /* The following kludgy code is to avoid some compiler bug.
-        We can't simply do
-        setup_coding_system (val, &coding);
-        on some system.  */
-      {
-       struct coding_system temp_coding;
-       setup_coding_system (Fcheck_coding_system (val), &temp_coding);
-       bcopy (&temp_coding, &coding, sizeof coding);
-      }
-      /* Ensure we set Vlast_coding_system_used.  */
-      set_coding_system = 1;
+      if (NILP (coding_system))
+       coding_system = Qundecided;
+      else
+       CHECK_CODING_SYSTEM (coding_system);
 
-      if (NILP (current_buffer->enable_multibyte_characters)
-         && ! NILP (val))
+      if (NILP (current_buffer->enable_multibyte_characters))
        /* We must suppress all character code conversion except for
           end-of-line conversion.  */
-       setup_raw_text_coding_system (&coding);
-      coding.src_multibyte = 0;
-      coding.dst_multibyte
-       = !NILP (current_buffer->enable_multibyte_characters);
+       coding_system = raw_text_coding_system (coding_system);
+      setup_coding_system (coding_system, &coding);
+      /* Ensure we set Vlast_coding_system_used.  */
+      set_coding_system = 1;
     }
 
-  if (!NILP (visit)
-      /* Can't do this if part of the buffer might be preserved.  */
-      && NILP (replace)
-      && (coding.type == coding_type_no_conversion
-         || coding.type == coding_type_raw_text))
+  if (!NILP (visit))
     {
-      /* Visiting a file with these coding system makes the buffer
-         unibyte. */
-      current_buffer->enable_multibyte_characters = Qnil;
-      coding.dst_multibyte = 0;
+      /* When we visit a file by raw-text, we change the buffer to
+        unibyte.  */
+      if (CODING_FOR_UNIBYTE (&coding)
+         /* Can't do this if part of the buffer might be preserved.  */
+         && NILP (replace))
+       /* Visiting a file with these coding system makes the buffer
+          unibyte. */
+       current_buffer->enable_multibyte_characters = Qnil;
     }
 
-  if (inserted > 0 || coding.type == coding_type_ccl)
+  coding.dst_multibyte = ! NILP (current_buffer->enable_multibyte_characters);
+  if (CODING_MAY_REQUIRE_DECODING (&coding)
+      && (inserted > 0 || CODING_REQUIRE_FLUSHING (&coding)))
     {
-      if (CODING_MAY_REQUIRE_DECODING (&coding))
-       {
-         if (coding.type == coding_type_ccl)
-           coding.spec.ccl.decoder.quit_silently = 1;
-         code_convert_region (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
-                              &coding, 0, 0);
-         if (coding.type == coding_type_ccl)
-           coding.spec.ccl.decoder.quit_silently = 0;
-         if (coding.result == CODING_FINISH_INTERRUPT)
-           {
-             /* Fixme: It is better that we report that the decoding
-                was interruppted by the user, and the current buffer
-                contents doesn't reflect the file correctly.  */
-             Fsignal (Qquit, Qnil);
-           }
-         inserted = coding.produced_char;
-       }
-      else
-       adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
-                            inserted);
+      move_gap_both (PT, PT_BYTE);
+      GAP_SIZE += inserted;
+      ZV_BYTE -= inserted;
+      Z_BYTE -= inserted;
+      ZV -= inserted;
+      Z -= inserted;
+      decode_coding_gap (&coding, inserted, inserted);
+      inserted = coding.produced_char;
+      coding_system = CODING_ID_NAME (coding.id);
     }
+  else if (inserted > 0)
+    adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
+                        inserted);
 
   /* Now INSERTED is measured in characters.  */
 
@@ -4666,8 +4651,8 @@ actually used.  */)
   /* Use the conversion type to determine buffer-file-type
      (find-buffer-file-type is now used to help determine the
      conversion).  */
-  if ((coding.eol_type == CODING_EOL_UNDECIDED
-       || coding.eol_type == CODING_EOL_LF)
+  if ((VECTORP (CODING_ID_EOL_TYPE (coding.id))
+       || EQ (CODING_ID_EOL_TYPE (coding.id), Qunix))
       && ! CODING_REQUIRE_DECODING (&coding))
     current_buffer->buffer_file_type = Qt;
   else
@@ -4678,11 +4663,8 @@ actually used.  */)
 
   if (!NILP (visit))
     {
-      if (!EQ (current_buffer->undo_list, Qt))
+      if (!EQ (current_buffer->undo_list, Qt) && !nochange)
        current_buffer->undo_list = Qnil;
-#ifdef APOLLO
-      stat (SDATA (filename), &st);
-#endif
 
       if (NILP (handler))
        {
@@ -4707,7 +4689,7 @@ actually used.  */)
     }
 
   if (set_coding_system)
-    Vlast_coding_system_used = coding.symbol;
+    Vlast_coding_system_used = coding_system;
 
   if (! NILP (Ffboundp (Qafter_insert_file_set_coding)))
     {
@@ -4723,24 +4705,119 @@ actually used.  */)
   /* Decode file format */
   if (inserted > 0)
     {
-      int empty_undo_list_p = 0;
+      /* Don't run point motion or modification hooks when decoding. */
+      int count = SPECPDL_INDEX ();
+      specbind (Qinhibit_point_motion_hooks, Qt);
+      specbind (Qinhibit_modification_hooks, Qt);
+
+      /* Save old undo list and don't record undo for decoding. */
+      old_undo = current_buffer->undo_list;
+      current_buffer->undo_list = Qt;
 
-      /* If we're anyway going to discard undo information, don't
-        record it in the first place.  The buffer's undo list at this
-        point is either nil or t when visiting a file.  */
-      if (!NILP (visit))
+      if (NILP (replace))
        {
-         empty_undo_list_p = NILP (current_buffer->undo_list);
-         current_buffer->undo_list = Qt;
+         insval = call3 (Qformat_decode,
+                         Qnil, make_number (inserted), visit);
+         CHECK_NUMBER (insval);
+         inserted = XFASTINT (insval);
+       }
+      else
+       {
+         /* If REPLACE is non-nil and we succeeded in not replacing the
+         beginning or end of the buffer text with the file's contents,
+         call format-decode with `point' positioned at the beginning of
+         the buffer and `inserted' equalling the number of characters
+         in the buffer.  Otherwise, format-decode might fail to
+         correctly analyze the beginning or end of the buffer.  Hence
+         we temporarily save `point' and `inserted' here and restore
+         `point' iff format-decode did not insert or delete any text.
+         Otherwise we leave `point' at point-min. */
+         int opoint = PT;
+         int opoint_byte = PT_BYTE;
+         int oinserted = ZV - BEGV;
+         int ochars_modiff = CHARS_MODIFF;
+
+         TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+         insval = call3 (Qformat_decode,
+                         Qnil, make_number (oinserted), visit);
+         CHECK_NUMBER (insval);
+         if (ochars_modiff == CHARS_MODIFF)
+           /* format_decode didn't modify buffer's characters => move
+              point back to position before inserted text and leave
+              value of inserted alone. */
+           SET_PT_BOTH (opoint, opoint_byte);
+         else
+           /* format_decode modified buffer's characters => consider
+              entire buffer changed and leave point at point-min. */
+           inserted = XFASTINT (insval);
+       }
+
+      /* For consistency with format-decode call these now iff inserted > 0
+        (martin 2007-06-28) */
+      p = Vafter_insert_file_functions;
+      while (CONSP (p))
+       {
+         if (NILP (replace))
+           {
+             insval = call1 (XCAR (p), make_number (inserted));
+             if (!NILP (insval))
+               {
+                 CHECK_NUMBER (insval);
+                 inserted = XFASTINT (insval);
+               }
+           }
+         else
+           {
+             /* For the rationale of this see the comment on format-decode above. */
+             int opoint = PT;
+             int opoint_byte = PT_BYTE;
+             int oinserted = ZV - BEGV;
+             int ochars_modiff = CHARS_MODIFF;
+
+             TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+             insval = call1 (XCAR (p), make_number (oinserted));
+             if (!NILP (insval))
+               {
+                 CHECK_NUMBER (insval);
+                 if (ochars_modiff == CHARS_MODIFF)
+                   /* after_insert_file_functions didn't modify
+                      buffer's characters => move point back to
+                      position before inserted text and leave value of
+                      inserted alone. */
+                   SET_PT_BOTH (opoint, opoint_byte);
+                 else
+                   /* after_insert_file_functions did modify buffer's
+                      characters => consider entire buffer changed and
+                      leave point at point-min. */
+                   inserted = XFASTINT (insval);
+               }
+           }
+
+         QUIT;
+         p = XCDR (p);
        }
 
-      insval = call3 (Qformat_decode,
-                     Qnil, make_number (inserted), visit);
-      CHECK_NUMBER (insval);
-      inserted = XFASTINT (insval);
+      if (NILP (visit))
+       {
+         Lisp_Object lbeg, lend;
+         XSETINT (lbeg, PT);
+         XSETINT (lend, PT + inserted);
+         if (CONSP (old_undo))
+           {
+             Lisp_Object tem = XCAR (old_undo);
+             if (CONSP (tem) && INTEGERP (XCAR (tem)) &&
+                 INTEGERP (XCDR (tem)) && EQ (XCAR (tem), lbeg))
+               /* In the non-visiting case record only the final insertion. */
+               current_buffer->undo_list =
+                 Fcons (Fcons (lbeg, lend), Fcdr (old_undo));
+           }
+       }
+      else
+       /* If undo_list was Qt before, keep it that way.
+          Otherwise start with an empty undo_list. */
+       current_buffer->undo_list = EQ (old_undo, Qt) ? Qt : Qnil;
 
-      if (!NILP (visit))
-       current_buffer->undo_list = empty_undo_list_p ? Qnil : Qt;
+      unbind_to (count, Qnil);
     }
 
   /* Call after-change hooks for the inserted text, aside from the case
@@ -4753,19 +4830,6 @@ actually used.  */)
       update_compositions (PT, PT, CHECK_BORDER);
     }
 
-  p = Vafter_insert_file_functions;
-  while (CONSP (p))
-    {
-      insval = call1 (XCAR (p), make_number (inserted));
-      if (!NILP (insval))
-       {
-         CHECK_NUMBER (insval);
-         inserted = XFASTINT (insval);
-       }
-      QUIT;
-      p = XCDR (p);
-    }
-
   if (!NILP (visit)
       && current_buffer->modtime == -1)
     {
@@ -4786,8 +4850,6 @@ actually used.  */)
 }
 \f
 static Lisp_Object build_annotations P_ ((Lisp_Object, Lisp_Object));
-static Lisp_Object build_annotations_2 P_ ((Lisp_Object, Lisp_Object,
-                                           Lisp_Object, Lisp_Object));
 
 /* If build_annotations switched buffers, switch back to BUF.
    Kill the temporary buffer that was selected in the meantime.
@@ -4812,26 +4874,21 @@ build_annotations_unwind (buf)
 
 /* Decide the coding-system to encode the data with.  */
 
-void
+static Lisp_Object
 choose_write_coding_system (start, end, filename,
                            append, visit, lockname, coding)
      Lisp_Object start, end, filename, append, visit, lockname;
      struct coding_system *coding;
 {
   Lisp_Object val;
+  Lisp_Object eol_parent = Qnil;
 
   if (auto_saving
       && NILP (Fstring_equal (current_buffer->filename,
                              current_buffer->auto_save_file_name)))
     {
-      /* We use emacs-mule for auto saving... */
-      setup_coding_system (Qemacs_mule, coding);
-      /* ... but with the special flag to indicate not to strip off
-        leading code of eight-bit-control chars.  */
-      coding->flags = 1;
-      /* We force LF for end-of-line because that is faster.  */
-      coding->eol_type = CODING_EOL_LF;
-      goto done_setup_coding;
+      val = Qutf_8_emacs;
+      eol_parent = Qunix;
     }
   else if (!NILP (Vcoding_system_for_write))
     {
@@ -4879,8 +4936,7 @@ choose_write_coding_system (start, end, filename,
            val = XCDR (coding_systems);
        }
 
-      if (NILP (val)
-         && !NILP (current_buffer->buffer_file_coding_system))
+      if (NILP (val))
        {
          /* If we still have not decided a coding system, use the
             default value of buffer-file-coding-system.  */
@@ -4888,45 +4944,42 @@ choose_write_coding_system (start, end, filename,
          using_default_coding = 1;
        }
 
+      if (! NILP (val) && ! force_raw_text)
+       {
+         Lisp_Object spec, attrs;
+
+         CHECK_CODING_SYSTEM_GET_SPEC (val, spec);
+         attrs = AREF (spec, 0);
+         if (EQ (CODING_ATTR_TYPE (attrs), Qraw_text))
+           force_raw_text = 1;
+       }
+
       if (!force_raw_text
          && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
        /* Confirm that VAL can surely encode the current region.  */
        val = call5 (Vselect_safe_coding_system_function,
                     start, end, val, Qnil, filename);
 
-      setup_coding_system (Fcheck_coding_system (val), coding);
-      if (coding->eol_type == CODING_EOL_UNDECIDED
-         && !using_default_coding)
-       {
-         if (! EQ (default_buffer_file_coding.symbol,
-                   buffer_defaults.buffer_file_coding_system))
-           setup_coding_system (buffer_defaults.buffer_file_coding_system,
-                                &default_buffer_file_coding);
-         if (default_buffer_file_coding.eol_type != CODING_EOL_UNDECIDED)
-           {
-             Lisp_Object subsidiaries;
-
-             coding->eol_type = default_buffer_file_coding.eol_type;
-             subsidiaries = Fget (coding->symbol, Qeol_type);
-             if (VECTORP (subsidiaries)
-                 && XVECTOR (subsidiaries)->size == 3)
-               coding->symbol
-                 = XVECTOR (subsidiaries)->contents[coding->eol_type];
-           }
-       }
+      /* If the decided coding-system doesn't specify end-of-line
+        format, we use that of
+        `default-buffer-file-coding-system'.  */
+      if (! using_default_coding
+         && ! NILP (buffer_defaults.buffer_file_coding_system))
+       val = (coding_inherit_eol_type
+              (val, buffer_defaults.buffer_file_coding_system));
 
+      /* If we decide not to encode text, use `raw-text' or one of its
+        subsidiaries.  */
       if (force_raw_text)
-       setup_raw_text_coding_system (coding);
-      goto done_setup_coding;
+       val = raw_text_coding_system (val);
     }
 
-  setup_coding_system (Fcheck_coding_system (val), coding);
+  val = coding_inherit_eol_type (val, eol_parent);
+  setup_coding_system (val, coding);
 
- done_setup_coding:
-  if (coding->eol_type == CODING_EOL_UNDECIDED)
-    coding->eol_type = system_eol_type;
   if (!STRINGP (start) && !NILP (current_buffer->selective_display))
     coding->mode |= CODING_MODE_SELECTIVE_DISPLAY;
+  return val;
 }
 
 DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 7,
@@ -4971,7 +5024,6 @@ This does code conversion according to the value of
   int save_errno = 0;
   const unsigned char *fn;
   struct stat st;
-  int tem;
   int count = SPECPDL_INDEX ();
   int count1;
 #ifdef VMS
@@ -5071,21 +5123,9 @@ This does code conversion according to the value of
      We used to make this choice before calling build_annotations, but that
      leads to problems when a write-annotate-function takes care of
      unsavable chars (as was the case with X-Symbol).  */
-  choose_write_coding_system (start, end, filename,
-                             append, visit, lockname, &coding);
-  Vlast_coding_system_used = coding.symbol;
-
-  given_buffer = current_buffer;
-  if (! STRINGP (start))
-    {
-      annotations = build_annotations_2 (start, end,
-                                        coding.pre_write_conversion, annotations);
-      if (current_buffer != given_buffer)
-       {
-         XSETFASTINT (start, BEGV);
-         XSETFASTINT (end, ZV);
-       }
-    }
+  Vlast_coding_system_used
+    = choose_write_coding_system (start, end, filename,
+                                 append, visit, lockname, &coding);
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
@@ -5223,6 +5263,9 @@ This does code conversion according to the value of
   if (GPT > BEG && GPT_ADDR[-1] != '\n')
     move_gap (find_next_newline (GPT, 1));
 #else
+#if 0
+  /* The new encoding routine doesn't require the following.  */
+
   /* Whether VMS or not, we must move the gap to the next of newline
      when we must put designation sequences at beginning of line.  */
   if (INTEGERP (start)
@@ -5235,6 +5278,7 @@ This does code conversion according to the value of
       move_gap_both (PT, PT_BYTE);
       SET_PT_BOTH (opoint, opoint_byte);
     }
+#endif
 #endif
 
   failure = 0;
@@ -5248,23 +5292,10 @@ This does code conversion according to the value of
     }
   else if (XINT (start) != XINT (end))
     {
-      tem = CHAR_TO_BYTE (XINT (start));
-
-      if (XINT (start) < GPT)
-       {
-         failure = 0 > a_write (desc, Qnil, XINT (start),
-                                min (GPT, XINT (end)) - XINT (start),
-                                &annotations, &coding);
-         save_errno = errno;
-       }
-
-      if (XINT (end) > GPT && !failure)
-       {
-         tem = max (XINT (start), GPT);
-         failure = 0 > a_write (desc, Qnil, tem , XINT (end) - tem,
-                                &annotations, &coding);
-         save_errno = errno;
-       }
+      failure = 0 > a_write (desc, Qnil,
+                            XINT (start), XINT (end) - XINT (start),
+                            &annotations, &coding);
+      save_errno = errno;
     }
   else
     {
@@ -5280,7 +5311,7 @@ This does code conversion according to the value of
     {
       /* We have to flush out a data. */
       coding.mode |= CODING_MODE_LAST_BLOCK;
-      failure = 0 > e_write (desc, Qnil, 0, 0, &coding);
+      failure = 0 > e_write (desc, Qnil, 1, 1, &coding);
       save_errno = errno;
     }
 
@@ -5309,15 +5340,13 @@ This does code conversion according to the value of
      but who knows about all the other machines with NFS?)  */
 #if 0
 
-  /* On VMS and APOLLO, must do the stat after the close
+  /* On VMS, must do the stat after the close
      since closing changes the modtime.  */
 #ifndef VMS
-#ifndef APOLLO
   /* Recall that #if defined does not work on VMS.  */
 #define FOO
   fstat (desc, &st);
 #endif
-#endif
 #endif
 
   /* NFS can report a write failure now.  */
@@ -5479,30 +5508,6 @@ build_annotations (start, end)
   return annotations;
 }
 
-static Lisp_Object
-build_annotations_2 (start, end, pre_write_conversion, annotations)
-     Lisp_Object start, end, pre_write_conversion, annotations;
-{
-  struct gcpro gcpro1;
-  Lisp_Object res;
-
-  GCPRO1 (annotations);
-  /* At last, do the same for the function PRE_WRITE_CONVERSION
-     implied by the current coding-system.  */
-  if (!NILP (pre_write_conversion))
-    {
-      struct buffer *given_buffer = current_buffer;
-      Vwrite_region_annotations_so_far = annotations;
-      res = call2 (pre_write_conversion, start, end);
-      Flength (res);
-      annotations = (current_buffer != given_buffer
-                    ? res
-                    : merge (annotations, res, Qcar_less_than_car));
-    }
-
-  UNGCPRO;
-  return annotations;
-}
 \f
 /* Write to descriptor DESC the NCHARS chars starting at POS of STRING.
    If STRING is nil, POS is the character position in the current buffer.
@@ -5558,9 +5563,6 @@ a_write (desc, string, pos, nchars, annot, coding)
   return 0;
 }
 
-#ifndef WRITE_BUF_SIZE
-#define WRITE_BUF_SIZE (16 * 1024)
-#endif
 
 /* Write text in the range START and END into descriptor DESC,
    encoding them with coding system CODING.  If STRING is nil, START
@@ -5574,78 +5576,77 @@ e_write (desc, string, start, end, coding)
      int start, end;
      struct coding_system *coding;
 {
-  register char *addr;
-  register int nbytes;
-  char buf[WRITE_BUF_SIZE];
-  int return_val = 0;
-
-  if (start >= end)
-    coding->composing = COMPOSITION_DISABLED;
-  if (coding->composing != COMPOSITION_DISABLED)
-    coding_save_composition (coding, start, end, string);
-
   if (STRINGP (string))
     {
-      addr = SDATA (string);
-      nbytes = SBYTES (string);
-      coding->src_multibyte = STRING_MULTIBYTE (string);
-    }
-  else if (start < end)
-    {
-      /* It is assured that the gap is not in the range START and END-1.  */
-      addr = CHAR_POS_ADDR (start);
-      nbytes = CHAR_TO_BYTE (end) - CHAR_TO_BYTE (start);
-      coding->src_multibyte
-       = !NILP (current_buffer->enable_multibyte_characters);
-    }
-  else
-    {
-      addr = "";
-      nbytes = 0;
-      coding->src_multibyte = 1;
+      start = 0;
+      end = SCHARS (string);
     }
 
   /* We used to have a code for handling selective display here.  But,
      now it is handled within encode_coding.  */
-  while (1)
-    {
-      int result;
 
-      result = encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
-      if (coding->produced > 0)
+  while (start < end)
+    {
+      if (STRINGP (string))
        {
-         coding->produced -= emacs_write (desc, buf, coding->produced);
-         if (coding->produced)
+         coding->src_multibyte = SCHARS (string) < SBYTES (string);
+         if (CODING_REQUIRE_ENCODING (coding))
            {
-             return_val = -1;
-             break;
+             encode_coding_object (coding, string,
+                                   start, string_char_to_byte (string, start),
+                                   end, string_char_to_byte (string, end), Qt);
+           }
+         else
+           {
+             coding->dst_object = string;
+             coding->consumed_char = SCHARS (string);
+             coding->produced = SBYTES (string);
            }
        }
-      nbytes -= coding->consumed;
-      addr += coding->consumed;
-      if (result == CODING_FINISH_INSUFFICIENT_SRC
-         && nbytes > 0)
+      else
        {
-         /* The source text ends by an incomplete multibyte form.
-             There's no way other than write it out as is.  */
-         nbytes -= emacs_write (desc, addr, nbytes);
-         if (nbytes)
+         int start_byte = CHAR_TO_BYTE (start);
+         int end_byte = CHAR_TO_BYTE (end);
+
+         coding->src_multibyte = (end - start) < (end_byte - start_byte);
+         if (CODING_REQUIRE_ENCODING (coding))
            {
-             return_val = -1;
-             break;
+             encode_coding_object (coding, Fcurrent_buffer (),
+                                   start, start_byte, end, end_byte, Qt);
+           }
+         else
+           {
+             coding->dst_object = Qnil;
+             coding->dst_pos_byte = start_byte;
+             if (start >= GPT || end <= GPT)
+               {
+                 coding->consumed_char = end - start;
+                 coding->produced = end_byte - start_byte;
+               }
+             else
+               {
+                 coding->consumed_char = GPT - start;
+                 coding->produced = GPT_BYTE - start_byte;
+               }
            }
        }
-      if (nbytes <= 0)
-       break;
+
+      if (coding->produced > 0)
+       {
+         coding->produced -=
+           emacs_write (desc,
+                        STRINGP (coding->dst_object)
+                        ? SDATA (coding->dst_object)
+                        : BYTE_POS_ADDR (coding->dst_pos_byte),
+                        coding->produced);
+
+         if (coding->produced)
+           return -1;
+       }
       start += coding->consumed_char;
-      if (coding->cmp_data)
-       coding_adjust_composition_offset (coding, start);
     }
 
-  if (coding->cmp_data)
-    coding_free_composition_data (coding);
-
-  return return_val;
+  return 0;
 }
 \f
 DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
@@ -5767,7 +5768,7 @@ auto_save_error (error)
 
   auto_save_error_occurred = 1;
 
-  ring_bell ();
+  ring_bell (XFRAME (selected_frame));
 
   args[0] = build_string ("Auto-saving %s: %s");
   args[1] = current_buffer->name;
@@ -5949,7 +5950,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
      couldn't handle some ange-ftp'd file.  */
 
   for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
-    for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
+    for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
       {
        buf = XCDR (XCAR (tail));
        b = XBUFFER (buf);
@@ -6138,135 +6139,6 @@ double_dollars (val)
   return val;
 }
 
-static Lisp_Object
-read_file_name_cleanup (arg)
-     Lisp_Object arg;
-{
-  return (current_buffer->directory = arg);
-}
-
-DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
-       3, 3, 0,
-       doc: /* Internal subroutine for read-file-name.  Do not call this.  */)
-     (string, dir, action)
-     Lisp_Object string, dir, action;
-  /* action is nil for complete, t for return list of completions,
-     lambda for verify final value */
-{
-  Lisp_Object name, specdir, realdir, val, orig_string;
-  int changed;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-
-  CHECK_STRING (string);
-
-  realdir = dir;
-  name = string;
-  orig_string = Qnil;
-  specdir = Qnil;
-  changed = 0;
-  /* No need to protect ACTION--we only compare it with t and nil.  */
-  GCPRO5 (string, realdir, name, specdir, orig_string);
-
-  if (SCHARS (string) == 0)
-    {
-      if (EQ (action, Qlambda))
-       {
-         UNGCPRO;
-         return Qnil;
-       }
-    }
-  else
-    {
-      orig_string = string;
-      string = Fsubstitute_in_file_name (string);
-      changed = NILP (Fstring_equal (string, orig_string));
-      name = Ffile_name_nondirectory (string);
-      val = Ffile_name_directory (string);
-      if (! NILP (val))
-       realdir = Fexpand_file_name (val, realdir);
-    }
-
-  if (NILP (action))
-    {
-      specdir = Ffile_name_directory (string);
-      val = Ffile_name_completion (name, realdir, Vread_file_name_predicate);
-      UNGCPRO;
-      if (!STRINGP (val))
-       {
-         if (changed)
-           return double_dollars (string);
-         return val;
-       }
-
-      if (!NILP (specdir))
-       val = concat2 (specdir, val);
-#ifndef VMS
-      return double_dollars (val);
-#else /* not VMS */
-      return val;
-#endif /* not VMS */
-    }
-  UNGCPRO;
-
-  if (EQ (action, Qt))
-    {
-      Lisp_Object all = Ffile_name_all_completions (name, realdir);
-      Lisp_Object comp;
-      int count;
-
-      if (NILP (Vread_file_name_predicate)
-         || EQ (Vread_file_name_predicate, Qfile_exists_p))
-       return all;
-
-#ifndef VMS
-      if (EQ (Vread_file_name_predicate, Qfile_directory_p))
-       {
-         /* Brute-force speed up for directory checking:
-            Discard strings which don't end in a slash.  */
-         for (comp = Qnil; CONSP (all); all = XCDR (all))
-           {
-             Lisp_Object tem = XCAR (all);
-             int len;
-             if (STRINGP (tem)
-                 && (len = SBYTES (tem), len > 0)
-                 && IS_DIRECTORY_SEP (SREF (tem, len-1)))
-               comp = Fcons (tem, comp);
-           }
-       }
-      else
-#endif
-       {
-         /* Must do it the hard (and slow) way.  */
-         Lisp_Object tem;
-         GCPRO3 (all, comp, specdir);
-         count = SPECPDL_INDEX ();
-         record_unwind_protect (read_file_name_cleanup, current_buffer->directory);
-         current_buffer->directory = realdir;
-         for (comp = Qnil; CONSP (all); all = XCDR (all))
-           {
-             tem = call1 (Vread_file_name_predicate, XCAR (all));
-             if (!NILP (tem))
-               comp = Fcons (XCAR (all), comp);
-           }
-         unbind_to (count, Qnil);
-         UNGCPRO;
-       }
-      return Fnreverse (comp);
-    }
-
-  /* Only other case actually used is ACTION = lambda */
-#ifdef VMS
-  /* Supposedly this helps commands such as `cd' that read directory names,
-     but can someone explain how it helps them? -- RMS */
-  if (SCHARS (name) == 0)
-    return Qt;
-#endif /* VMS */
-  string = Fexpand_file_name (string, dir);
-  if (!NILP (Vread_file_name_predicate))
-    return call1 (Vread_file_name_predicate, string);
-  return Ffile_exists_p (string);
-}
-
 DEFUN ("next-read-file-uses-dialog-p", Fnext_read_file_uses_dialog_p,
        Snext_read_file_uses_dialog_p, 0, 0, 0,
        doc: /* Return t if a call to `read-file-name' will use a dialog.
@@ -6332,7 +6204,7 @@ and `read-file-name-function'.  */)
   /* If dir starts with user's homedir, change that to ~. */
   homedir = (char *) egetenv ("HOME");
 #ifdef DOS_NT
-  /* homedir can be NULL in temacs, since Vprocess_environment is not
+  /* homedir can be NULL in temacs, since Vglobal_environment is not
      yet set up.  We shouldn't crash in that case.  */
   if (homedir != 0)
     {
@@ -6454,7 +6326,7 @@ and `read-file-name-function'.  */)
       if (! replace_in_history)
        add_to_history = 1;
 
-      val = empty_string;
+      val = empty_unibyte_string;
     }
 
   unbind_to (count, Qnil);
@@ -6713,8 +6585,9 @@ or local variable spec of the tailing lines with `coding:' tag.  */);
 
   DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
               doc: /* A list of functions to be called at the end of `insert-file-contents'.
-Each is passed one argument, the number of characters inserted.
-It should return the new character count, and leave point the same.
+Each is passed one argument, the number of characters inserted,
+with point at the start of the inserted text.  Each function
+should leave point the same, and return the new character count.
 If `insert-file-contents' is intercepted by a handler from
 `file-name-handler-alist', that handler is responsible for calling the
 functions in `after-insert-file-functions' if appropriate.  */);
@@ -6819,7 +6692,6 @@ A non-nil value may result in data loss!  */);
   defsubr (&Sclear_buffer_auto_save_failure);
   defsubr (&Srecent_auto_save_p);
 
-  defsubr (&Sread_file_name_internal);
   defsubr (&Sread_file_name);
   defsubr (&Snext_read_file_uses_dialog_p);