(x_wm_set_size_hint): Always set PWinGravity.
[bpt/emacs.git] / src / fileio.c
index b106699..36e8ba0 100644 (file)
@@ -22,6 +22,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #if !defined (S_ISLNK) && defined (S_IFLNK)
 #  define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
 #endif
@@ -44,7 +48,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <ctype.h>
 
 #ifdef VMS
-#include "dir.h"
+#include "vmsdir.h"
 #include <perror.h>
 #include <stddef.h>
 #include <string.h>
@@ -125,6 +129,16 @@ int insert_default_directory;
    Zero means use var format.  */
 int vms_stmlf_recfm;
 
+/* These variables describe handlers that have "already" had a chance
+   to handle the current operation.
+
+   Vinhibit_file_name_handlers is a list of file name handlers.
+   Vinhibit_file_name_operation is the operation being handled.
+   If we try to handle that operation, we ignore those handlers.  */
+
+static Lisp_Object Vinhibit_file_name_handlers;
+static Lisp_Object Vinhibit_file_name_operation;
+
 Lisp_Object Qfile_error, Qfile_already_exists;
 
 Lisp_Object Qfile_name_history;
@@ -154,6 +168,15 @@ close_file_unwind (fd)
 {
   close (XFASTINT (fd));
 }
+
+/* Restore point, having saved it as a marker.  */
+
+restore_point_unwind (location)
+     Lisp_Object location; 
+{
+  SET_PT (marker_position (location));
+  Fset_marker (location, Qnil, Qnil);
+}
 \f
 Lisp_Object Qexpand_file_name;
 Lisp_Object Qdirectory_file_name;
@@ -183,19 +206,28 @@ Lisp_Object Qwrite_region;
 Lisp_Object Qverify_visited_file_modtime;
 Lisp_Object Qset_visited_file_modtime;
 
-DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 1, 1, 0,
-  "Return FILENAME's handler function, if its syntax is handled specially.\n\
+DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 2, 2, 0,
+  "Return FILENAME's handler function for OPERATION, if it has one.\n\
 Otherwise, return nil.\n\
 A file name is handled if one of the regular expressions in\n\
-`file-name-handler-alist' matches it.")
-  (filename)
-    Lisp_Object filename;
+`file-name-handler-alist' matches it.\n\n\
+If OPERATION equals `inhibit-file-name-operation', then we ignore\n\
+any handlers that are members of `inhibit-file-name-handlers',\n\
+but we still do run any other handlers.  This lets handlers\n\
+use the standard functions without calling themselves recursively.")
+  (filename, operation)
+    Lisp_Object filename, operation;
 {
   /* This function must not munge the match data.  */
-  Lisp_Object chain;
+  Lisp_Object chain, inhibited_handlers;
 
   CHECK_STRING (filename, 0);
 
+  if (EQ (operation, Vinhibit_file_name_operation))
+    inhibited_handlers = Vinhibit_file_name_handlers;
+  else
+    inhibited_handlers = Qnil;
+
   for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
        chain = XCONS (chain)->cdr)
     {
@@ -207,7 +239,14 @@ A file name is handled if one of the regular expressions in\n\
          string = XCONS (elt)->car;
          if (XTYPE (string) == Lisp_String
              && fast_string_match (string, filename) >= 0)
-           return XCONS (elt)->cdr;
+           {
+             Lisp_Object handler, tem;
+
+             handler = XCONS (elt)->cdr;
+             tem = Fmemq (handler, inhibited_handlers);
+             if (NILP (tem))
+               return handler;
+           }
        }
 
       QUIT;
@@ -233,7 +272,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (file);
+  handler = Ffind_file_name_handler (file, Qfile_name_directory);
   if (!NILP (handler))
     return call2 (handler, Qfile_name_directory, file);
 
@@ -291,7 +330,7 @@ or the entire name if it contains no slash.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (file);
+  handler = Ffind_file_name_handler (file, Qfile_name_nondirectory);
   if (!NILP (handler))
     return call2 (handler, Qfile_name_nondirectory, file);
 
@@ -325,7 +364,7 @@ get a current directory to run processes in.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qunhandled_file_name_directory);
   if (!NILP (handler))
     return call2 (handler, Qunhandled_file_name_directory, filename);
 
@@ -431,7 +470,7 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (file);
+  handler = Ffind_file_name_handler (file, Qfile_name_as_directory);
   if (!NILP (handler))
     return call2 (handler, Qfile_name_as_directory, file);
 
@@ -612,7 +651,7 @@ it returns a file name such as \"[X]Y.DIR.1\".")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (directory);
+  handler = Ffind_file_name_handler (directory, Qdirectory_file_name);
   if (!NILP (handler))
     return call2 (handler, Qdirectory_file_name, directory);
 
@@ -681,7 +720,7 @@ See also the function `substitute-in-file-name'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (name);
+  handler = Ffind_file_name_handler (name, Qexpand_file_name);
   if (!NILP (handler))
     return call3 (handler, Qexpand_file_name, name, defalt);
 
@@ -1527,13 +1566,6 @@ duplicates what `expand-file-name' does.")
 
        /* Get variable value */
        o = (unsigned char *) egetenv (target);
-/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
-#if 0
-#ifdef USG
-       if (!o && !strcmp (target, "USER"))
-         o = egetenv ("LOGNAME");
-#endif /* USG */
-#endif /* 0 */
        if (!o) goto badvar;
        total += strlen (o);
        substituted = 1;
@@ -1585,13 +1617,6 @@ duplicates what `expand-file-name' does.")
 
        /* Get variable value */
        o = (unsigned char *) egetenv (target);
-/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
-#if 0
-#ifdef USG
-       if (!o && !strcmp (target, "USER"))
-         o = egetenv ("LOGNAME");
-#endif /* USG */
-#endif /* 0 */
        if (!o)
          goto badvar;
 
@@ -1715,13 +1740,13 @@ A prefix arg makes KEEP-TIME non-nil.")
 
   /* If the input file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qcopy_file);
   /* Likewise for output file name.  */
   if (NILP (handler))
-    handler = Ffind_file_name_handler (newname);
+    handler = Ffind_file_name_handler (newname, Qcopy_file);
   if (!NILP (handler))
-    return call5 (handler, Qcopy_file, filename, newname,
-                 ok_if_already_exists, keep_date);
+    RETURN_UNGCPRO (call5 (handler, Qcopy_file, filename, newname,
+                          ok_if_already_exists, keep_date));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1813,7 +1838,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
   CHECK_STRING (dirname, 0);
   dirname = Fexpand_file_name (dirname, Qnil);
 
-  handler = Ffind_file_name_handler (dirname);
+  handler = Ffind_file_name_handler (dirname, Qmake_directory);
   if (!NILP (handler))
     return call3 (handler, Qmake_directory, dirname, Qnil);
 
@@ -1837,7 +1862,7 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
   dirname = Fexpand_file_name (dirname, Qnil);
   dir = XSTRING (dirname)->data;
 
-  handler = Ffind_file_name_handler (dirname);
+  handler = Ffind_file_name_handler (dirname, Qdelete_directory);
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, dirname);
 
@@ -1857,7 +1882,7 @@ If file has multiple names, it continues to exist with the other names.")
   CHECK_STRING (filename, 0);
   filename = Fexpand_file_name (filename, Qnil);
 
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qdelete_file);
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
@@ -1891,12 +1916,12 @@ This is what happens in interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qrename_file);
   if (NILP (handler))
-    handler = Ffind_file_name_handler (newname);
+    handler = Ffind_file_name_handler (newname, Qrename_file);
   if (!NILP (handler))
-    return call4 (handler, Qrename_file,
-                 filename, newname, ok_if_already_exists);
+    RETURN_UNGCPRO (call4 (handler, Qrename_file,
+                          filename, newname, ok_if_already_exists));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -1956,10 +1981,10 @@ This is what happens in interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qadd_name_to_file);
   if (!NILP (handler))
-    return call4 (handler, Qadd_name_to_file, filename, newname,
-                 ok_if_already_exists);
+    RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
+                          newname, ok_if_already_exists));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -2010,10 +2035,10 @@ This happens for interactive use with M-x.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qmake_symbolic_link);
   if (!NILP (handler))
-    return call4 (handler, Qmake_symbolic_link, filename, linkname,
-                 ok_if_already_exists);
+    RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
+                          linkname, ok_if_already_exists));
 
   if (NILP (ok_if_already_exists)
       || XTYPE (ok_if_already_exists) == Lisp_Int)
@@ -2131,7 +2156,7 @@ See also `file-readable-p' and `file-attributes'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_exists_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_exists_p, abspath);
 
@@ -2153,7 +2178,7 @@ For a directory, this means you can access files in that directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_executable_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_executable_p, abspath);
 
@@ -2174,7 +2199,7 @@ See also `file-exists-p' and `file-attributes'.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_readable_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_readable_p, abspath);
 
@@ -2200,7 +2225,7 @@ Otherwise returns nil.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qfile_symlink_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_symlink_p, filename);
 
@@ -2267,7 +2292,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_writable_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_writable_p, abspath);
 
@@ -2304,7 +2329,7 @@ if the directory so specified exists and really is a directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_directory_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_directory_p, abspath);
 
@@ -2327,7 +2352,7 @@ searchable directory.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
   if (!NILP (handler))
     return call2 (handler, Qfile_accessible_directory_p, filename);
 
@@ -2351,12 +2376,25 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qfile_modes);
   if (!NILP (handler))
     return call2 (handler, Qfile_modes, abspath);
 
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
+#ifdef MSDOS
+  {
+    int len;
+    char *suffix;
+    if (S_ISREG (st.st_mode)
+       && (len = XSTRING (abspath)->size) >= 5
+       && (stricmp ((suffix = XSTRING (abspath)->data + len-4), ".com") == 0
+           || stricmp (suffix, ".exe") == 0
+           || stricmp (suffix, ".bat") == 0))
+      st.st_mode |= S_IEXEC;
+  }
+#endif /* MSDOS */
+
   return make_number (st.st_mode & 07777);
 }
 
@@ -2374,7 +2412,7 @@ Only the 12 low bits of MODE are used.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath);
+  handler = Ffind_file_name_handler (abspath, Qset_file_modes);
   if (!NILP (handler))
     return call3 (handler, Qset_file_modes, abspath, mode);
 
@@ -2477,9 +2515,9 @@ otherwise, if FILE2 does not exist, the answer is t.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath1);
+  handler = Ffind_file_name_handler (abspath1, Qfile_newer_than_file_p);
   if (NILP (handler))
-    handler = Ffind_file_name_handler (abspath2);
+    handler = Ffind_file_name_handler (abspath2, Qfile_newer_than_file_p);
   if (!NILP (handler))
     return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
 
@@ -2499,7 +2537,7 @@ Lisp_Object Qfind_buffer_file_type;
 #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\
@@ -2508,9 +2546,14 @@ If visiting and the file does not exist, visiting is completed\n\
 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;
@@ -2534,10 +2577,11 @@ If VISIT is non-nil, BEG and END must be nil.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
   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;
     }
 
@@ -2559,6 +2603,10 @@ If VISIT is non-nil, BEG and END must be nil.")
       goto notfound;
     }
 
+  /* Replacement should preserve point as it preserves markers.  */
+  if (!NILP (replace))
+    record_unwind_protect (restore_point_unwind, Fpoint_marker ());
+
   record_unwind_protect (close_file_unwind, make_number (fd));
 
 #ifdef S_IFSOCK
@@ -2593,6 +2641,103 @@ If VISIT is non-nil, BEG and END must be nil.")
        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;
+      int overlap;
+
+      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 == st.st_size)
+       {
+         close (fd);
+         specpdl_ptr--;
+         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;
+
+      /* 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;
+
+      /* 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);
+
+      del_range_1 (same_at_start, same_at_end, 0);
+      /* Insert from the file at the proper position.  */
+      SET_PT (same_at_start);
+    }
+
   total = XINT (end) - XINT (beg);
 
   {
@@ -2611,13 +2756,14 @@ If VISIT is non-nil, BEG and END must be nil.")
   if (GAP_SIZE < total)
     make_gap (total - GAP_SIZE);
 
-  if (XINT (beg) != 0)
+  if (XINT (beg) != 0 || !NILP (replace))
     {
       if (lseek (fd, XINT (beg), 0) < 0)
        report_file_error ("Setting file position", Fcons (filename, Qnil));
     }
 
-  while (1)
+  how_much = 0;
+  while (inserted < total)
     {
       int try = min (total - inserted, 64 << 10);
       int this;
@@ -2647,16 +2793,16 @@ If VISIT is non-nil, BEG and END must be nil.")
      is deemed to be a text file.  */
   {
     struct gcpro gcpro1;
-    Lisp_Object code = Qnil;
+    Lisp_Object code;
+    code = Qnil;
     GCPRO1 (filename);
-    code = call1 (Qfind_buffer_file_type, filename);
+    current_buffer->buffer_file_type
+      = call1 (Qfind_buffer_file_type, filename);
     UNGCPRO;
-    if (XTYPE (code) == Lisp_Int) 
-      XFASTINT (current_buffer->buffer_file_type) = XFASTINT (code);
-    if (XFASTINT (current_buffer->buffer_file_type) == 0)
+    if (NILP (current_buffer->buffer_file_type))
       {
-       int reduced_size = 
-         inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
+       int reduced_size
+         inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
        ZV -= reduced_size;
        Z -= reduced_size;
        GPT -= reduced_size;
@@ -2677,8 +2823,8 @@ If VISIT is non-nil, BEG and END must be nil.")
 
   close (fd);
 
-  /* Discard the unwind protect */
-  specpdl_ptr = specpdl + count;
+  /* Discard the unwind protect for closing the file.  */
+  specpdl_ptr--;
 
   if (how_much < 0)
     error ("IO error reading %s: %s",
@@ -2689,7 +2835,8 @@ If VISIT is non-nil, BEG and END must be nil.")
 
   if (!NILP (visit))
     {
-      current_buffer->undo_list = Qnil;
+      if (!EQ (current_buffer->undo_list, Qt))
+       current_buffer->undo_list = Qnil;
 #ifdef APOLLO
       stat (XSTRING (filename)->data, &st);
 #endif
@@ -2735,11 +2882,12 @@ If VISIT is non-nil, BEG and END must be nil.")
        }
     }
 
-  if (!NILP (val))
-    RETURN_UNGCPRO (val);
-  RETURN_UNGCPRO (Fcons (filename,
-                        Fcons (make_number (inserted),
-                               Qnil)));
+  if (NILP (val))
+    val = Fcons (filename,
+                Fcons (make_number (inserted),
+                       Qnil));
+
+  RETURN_UNGCPRO (unbind_to (count, val));
 }
 \f
 static Lisp_Object build_annotations ();
@@ -2802,7 +2950,10 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename);
+  handler = Ffind_file_name_handler (filename, Qwrite_region);
+  /* If FILENAME has no handler, see if VISIT has one.  */
+  if (NILP (handler) && XTYPE (visit) == Lisp_String)
+    handler = Ffind_file_name_handler (visit, Qwrite_region);    
 
   if (!NILP (handler))
     {
@@ -3195,7 +3346,8 @@ This means that the file has not been changed since it was visited or saved.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (b->filename);
+  handler = Ffind_file_name_handler (b->filename,
+                                    Qverify_visited_file_modtime);
   if (!NILP (handler))
     return call2 (handler, Qverify_visited_file_modtime, buf);
 
@@ -3260,7 +3412,7 @@ An argument specifies the modification time value to use\n\
 
       /* If the file name has special constructs in it,
         call the corresponding file handler.  */
-      handler = Ffind_file_name_handler (filename);
+      handler = Ffind_file_name_handler (filename, Qset_visited_file_modtime);
       if (!NILP (handler))
        /* The handler can find the file name the same way we did.  */
        return call2 (handler, Qset_visited_file_modtime, Qnil);
@@ -3311,7 +3463,8 @@ This is all buffers that have auto-saving enabled\n\
 and are changed since last auto-saved.\n\
 Auto-saving writes the buffer into a file\n\
 so that your editing is not lost if the system crashes.\n\
-This file is not the file you visited; that changes only when you save.\n\n\
+This file is not the file you visited; that changes only when you save.\n\
+Normally we run the normal hook `auto-save-hook' before saving.\n\n\
 Non-nil first argument means do not print any message if successful.\n\
 Non-nil second argument means save only current buffer.")
   (no_message, current_only)
@@ -3321,6 +3474,7 @@ Non-nil second argument means save only current buffer.")
   Lisp_Object tail, buf;
   int auto_saved = 0;
   char *omessage = echo_area_glyphs;
+  int omessage_length = echo_area_glyphs_length;
   extern int minibuf_level;
   int do_handled_files;
   Lisp_Object oquit;
@@ -3337,8 +3491,6 @@ Non-nil second argument means save only current buffer.")
   if (minibuf_level)
     no_message = Qt;
 
-  /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
-     eventually call do-auto-save, so don't err here in that case. */
   if (!NILP (Vrun_hooks))
     call1 (Vrun_hooks, intern ("auto-save-hook"));
 
@@ -3364,8 +3516,11 @@ Non-nil second argument means save only current buffer.")
        if (XTYPE (b->auto_save_file_name) == Lisp_String
            && b->save_modified < BUF_MODIFF (b)
            && b->auto_save_modified < BUF_MODIFF (b)
+           /* -1 means we've turned off autosaving for a while--see below.  */
+           && XINT (b->save_length) >= 0
            && (do_handled_files
-               || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
+               || NILP (Ffind_file_name_handler (b->auto_save_file_name,
+                                                 Qwrite_region))))
          {
            EMACS_TIME before_time, after_time;
 
@@ -3388,10 +3543,9 @@ Non-nil second argument means save only current buffer.")
                /* It has shrunk too much; turn off auto-saving here.  */
                message ("Buffer %s has shrunk a lot; auto save turned off there",
                         XSTRING (b->name)->data);
-               /* User can reenable saving with M-x auto-save.  */
-               b->auto_save_file_name = Qnil;
-               /* Prevent warning from repeating if user does so.  */
-               XFASTINT (b->save_length) = 0;
+               /* Turn off auto-saving until there's a real save,
+                  and prevent any more warnings.  */
+               XSET (b->save_length, Lisp_Int, -1);
                Fsleep_for (make_number (1), Qnil);
                continue;
              }
@@ -3417,7 +3571,12 @@ Non-nil second argument means save only current buffer.")
   record_auto_save ();
 
   if (auto_saved && NILP (no_message))
-    message1 (omessage ? omessage : "Auto-saving...done");
+    {
+      if (omessage)
+       message2 (omessage, omessage_length);
+      else
+       message1 ("Auto-saving...done");
+    }
 
   Vquit_flag = oquit;
 
@@ -3599,7 +3758,6 @@ DIR defaults to current buffer's directory default.")
   if (insert_default_directory)
     {
       insdef = dir;
-      insdef1 = dir;
       if (!NILP (initial))
        {
          Lisp_Object args[2], pos;
@@ -3607,12 +3765,17 @@ DIR defaults to current buffer's directory default.")
          args[0] = insdef;
          args[1] = initial;
          insdef = Fconcat (2, args);
-         pos = make_number (XSTRING (dir)->size);
+         pos = make_number (XSTRING (double_dollars (dir))->size);
          insdef1 = Fcons (double_dollars (insdef), pos);
        }
       else
        insdef1 = double_dollars (insdef);
     }
+  else if (!NILP (initial))
+    {
+      insdef = initial;
+      insdef1 = Fcons (double_dollars (insdef), 0);
+    }
   else
     insdef = Qnil, insdef1 = Qnil;
 
@@ -3648,14 +3811,9 @@ DIR defaults to current buffer's directory default.")
 
 #if 0                          /* Old version */
 DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
-  "Read file name, prompting with PROMPT and completing in directory DIR.\n\
-Value is not expanded---you must call `expand-file-name' yourself.\n\
-Default name to DEFAULT if user enters a null string.\n\
- (If DEFAULT is omitted, the visited file name is used.)\n\
-Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
- Non-nil and non-t means also require confirmation after completion.\n\
-Fifth arg INITIAL specifies text to start with.\n\
-DIR defaults to current buffer's directory default.")
+  /* Don't confuse make-docfile by having two doc strings for this function.
+     make-docfile does not pay attention to #if, for good reason!  */
+  0)
   (prompt, dir, defalt, mustmatch, initial)
      Lisp_Object prompt, dir, defalt, mustmatch, initial;
 {
@@ -3840,6 +3998,15 @@ increasing order.  If there are several functions in the list, the several\n\
 lists are merged destructively.");
   Vwrite_region_annotate_functions = Qnil;
 
+  DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
+    "A list of file names for which handlers should not be used.\n\
+This applies only to the operation `inhibit-file-name-operation'.");
+  Vinhibit_file_name_handlers = Qnil;
+
+  DEFVAR_LISP ("inhibit-file-name-operation", &Vinhibit_file_name_operation,
+    "The operation for which `inhibit-file-name-handlers' is applicable.");
+  Vinhibit_file_name_operation = Qnil;
+
   defsubr (&Sfind_file_name_handler);
   defsubr (&Sfile_name_directory);
   defsubr (&Sfile_name_nondirectory);