]> code.delx.au - gnu-emacs/blobdiff - src/fileio.c
[HAVE_X_WINDOWS] (HAVE_WINDOW_SYSTEM): New macro.
[gnu-emacs] / src / fileio.c
index 9772e4c5030214b74b9e392e4b86f21d50fc1bfb..f6f99e5e3056751d5656c25026c97cc31c197ea7 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94, 95 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -128,6 +128,12 @@ int auto_save_mode_bits;
    whose I/O is done with a special handler.  */
 Lisp_Object Vfile_name_handler_alist;
 
+/* Format for auto-save files */
+Lisp_Object Vauto_save_file_format;
+
+/* Lisp functions for translating file formats */
+Lisp_Object Qformat_decode, Qformat_annotate_function;
+
 /* Functions to be called to process text properties in inserted file.  */
 Lisp_Object Vafter_insert_file_functions;
 
@@ -199,6 +205,7 @@ restore_point_unwind (location)
 }
 \f
 Lisp_Object Qexpand_file_name;
+Lisp_Object Qsubstitute_in_file_name;
 Lisp_Object Qdirectory_file_name;
 Lisp_Object Qfile_name_directory;
 Lisp_Object Qfile_name_nondirectory;
@@ -217,6 +224,7 @@ Lisp_Object Qfile_readable_p;
 Lisp_Object Qfile_symlink_p;
 Lisp_Object Qfile_writable_p;
 Lisp_Object Qfile_directory_p;
+Lisp_Object Qfile_regular_p;
 Lisp_Object Qfile_accessible_directory_p;
 Lisp_Object Qfile_modes;
 Lisp_Object Qset_file_modes;
@@ -225,7 +233,6 @@ Lisp_Object Qinsert_file_contents;
 Lisp_Object Qwrite_region;
 Lisp_Object Qverify_visited_file_modtime;
 Lisp_Object Qset_visited_file_modtime;
-Lisp_Object Qsubstitute_in_file_name;
 
 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\
@@ -306,9 +313,6 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
 #ifdef VMS
         && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
 #endif /* VMS */
-#ifdef MSDOS
-        && p[-1] != ':' && p[-1] != '\\'
-#endif
         ) p--;
 
   if (p == beg)
@@ -372,9 +376,6 @@ or the entire name if it contains no slash.")
 #ifdef VMS
         && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
 #endif /* VMS */
-#ifdef MSDOS
-        && p[-1] != ':'
-#endif
         ) p--;
 
   return make_string (p, end - p);
@@ -470,15 +471,11 @@ file_name_as_directory (out, in)
     }
 #else /* not VMS */
   /* For Unix syntax, Append a slash if necessary */
-#ifdef MSDOS
-  if (out[size] != ':' && out[size] != '/' && out[size] != '\\')
-#else /* not MSDOS */
   if (!IS_ANY_SEP (out[size]))
     {
       out[size + 1] = DIRECTORY_SEP;
       out[size + 2] = '\0';
     }
-#endif /* not MSDOS */
 #endif /* not VMS */
   return out;
 }
@@ -653,10 +650,20 @@ 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])
-      && !IS_DEVICE_SEP (dst[slen - 2]))
+#ifdef DOS_NT
+      && !IS_ANY_SEP (dst[slen - 2])
+#endif
+      )
     dst[slen - 1] = 0;
+#endif
   return 1;
 }
 
@@ -761,6 +768,13 @@ See also the function `substitute-in-file-name'.")
     defalt = current_buffer->directory;
   CHECK_STRING (defalt, 1);
 
+  if (!NILP (defalt))
+    {
+      handler = Ffind_file_name_handler (defalt, Qexpand_file_name);
+      if (!NILP (handler))
+       return call3 (handler, Qexpand_file_name, name, defalt);
+    }
+
   o = XSTRING (defalt)->data;
 
   /* Make sure DEFALT is properly expanded.
@@ -810,17 +824,43 @@ See also the function `substitute-in-file-name'.")
        nm++;
       else
        {
-         drive = tolower (colon[-1]) - 'a';
+         drive = colon[-1];
          nm = colon + 1;
          if (!IS_DIRECTORY_SEP (*nm))
            {
              defdir = alloca (MAXPATHLEN + 1);
-             relpath = getdefdir (drive + 1, defdir);
+             relpath = getdefdir (tolower (drive) - 'a' + 1, defdir);
            }
        }       
   }
 #endif /* DOS_NT */
 
+  /* Handle // and /~ in middle of file name
+     by discarding everything through the first / of that sequence.  */
+  p = nm;
+  while (*p)
+    {
+      /* Since we know the path is absolute, we can assume that each
+        element starts with a "/".  */
+
+      /* "//" anywhere isn't necessarily hairy; we just start afresh
+        with the second slash.  */
+      if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
+#if defined (APOLLO) || defined (WINDOWSNT)
+         /* // at start of filename is meaningful on Apollo 
+            and WindowsNT systems */
+         && nm != p
+#endif /* APOLLO || WINDOWSNT */
+         )
+       nm = p + 1;
+
+      /* "~" is hairy as the start of any path element.  */
+      if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
+       nm = p + 1;
+
+      p++;
+    }
+
   /* If nm is absolute, flush ...// and detect /./ and /../.
      If no /./ or /../ we can return right away. */
   if (
@@ -844,24 +884,6 @@ See also the function `substitute-in-file-name'.")
          /* Since we know the path is absolute, we can assume that each
             element starts with a "/".  */
 
-         /* "//" anywhere isn't necessarily hairy; we just start afresh
-            with the second slash.  */
-         if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
-#ifdef APOLLO
-             /* // at start of filename is meaningful on Apollo system */
-             && nm != p
-#endif /* APOLLO */
-#ifdef WINDOWSNT
-             /* \\ or // at the start of a pathname is meaningful on NT.  */
-             && nm != p
-#endif /* WINDOWSNT */
-             )
-           nm = p + 1;
-
-         /* "~" is hairy as the start of any path element.  */
-         if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
-           nm = p + 1, lose = 1;
-
          /* "." and ".." are hairy.  */
          if (IS_DIRECTORY_SEP (p[0])
              && p[1] == '.'
@@ -974,6 +996,10 @@ See also the function `substitute-in-file-name'.")
          if (!(newdir = (unsigned char *) egetenv ("HOME")))
            newdir = (unsigned char *) "";
 #ifdef DOS_NT
+         /* Problem when expanding "~\" if HOME is not on current drive.
+            Ulrich Leodolter, Wed Jan 11 10:20:35 1995 */
+         if (newdir[1] == ':')
+           drive = newdir[0];
          dostounix_filename (newdir);
 #endif
          nm++;
@@ -1036,7 +1062,7 @@ See also the function `substitute-in-file-name'.")
       /* Adding `length > 1 &&' makes ~ expand into / when homedir
         is the root dir.  People disagree about whether that is right.
         Anyway, we can't take the risk of this change now.  */
-#ifdef MSDOS
+#ifdef DOS_NT
       if (newdir[1] != ':' && length > 1)
 #endif
       if (IS_DIRECTORY_SEP (newdir[length - 1]))
@@ -1132,19 +1158,12 @@ See also the function `substitute-in-file-name'.")
        {
          *o++ = *p++;
        }
-#ifdef WINDOWSNT
-      else if (!strncmp (p, "\\\\", 2) || !strncmp (p, "//", 2))
-#else  /* not WINDOWSNT */
-      else if (!strncmp (p, "//", 2)
-#endif /* not WINDOWSNT */
-#ifdef APOLLO
-              /* // at start of filename is meaningful in Apollo system */
+      else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
+#if defined (APOLLO) || defined (WINDOWSNT)
+              /* // at start of filename is meaningful in Apollo 
+                 and WindowsNT systems */
               && o != target
 #endif /* APOLLO */
-#ifdef WINDOWSNT
-              /* \\ at start of filename is meaningful in Windows-NT */
-              && o != target
-#endif /* WINDOWSNT */
               )
        {
          o = target;
@@ -1161,28 +1180,19 @@ See also the function `substitute-in-file-name'.")
            *o++ = *p;
          p += 2;
        }
-#ifdef WINDOWSNT
-      else if (!strncmp (p, "\\..", 3) || !strncmp (p, "/..", 3))
-#else  /* not WINDOWSNT */
-      else if (!strncmp (p, "/..", 3)
-#endif /* not WINDOWSNT */
+      else if (IS_DIRECTORY_SEP (p[0]) && p[1] == '.' && p[2] == '.'
               /* `/../' is the "superroot" on certain file systems.  */
               && o != target
               && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
        {
          while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
            ;
-#ifdef APOLLO
-         if (o == target + 1 && o[-1] == '/' && o[0] == '/')
-           ++o;
-         else
-#endif /* APOLLO */
-#ifdef WINDOWSNT
-         if (o == target + 1 && (o[-1] == '/' && o[0] == '/')
-             || (o[-1] == '\\' && o[0] == '\\'))
+#if defined (APOLLO) || defined (WINDOWSNT)
+         if (o == target + 1 
+             && IS_DIRECTORY_SEP (o[-1]) && IS_DIRECTORY_SEP (o[0]))
            ++o;
          else
-#endif /* WINDOWSNT */
+#endif /* APOLLO || WINDOWSNT */
          if (o == target && IS_ANY_SEP (*o))
            ++o;
          p += 3;
@@ -1204,7 +1214,7 @@ See also the function `substitute-in-file-name'.")
       )
     {
       target -= 2;
-      target[0] = (drive < 0 ? getdisk () : drive) + 'a';
+      target[0] = (drive < 0 ? getdisk () + 'A' : drive);
       target[1] = ':';
     }
 #endif /* DOS_NT */
@@ -1778,11 +1788,20 @@ expand_and_dir_to_file (filename, defdir)
   return abspath;
 }
 \f
+/* Signal an error if the file ABSNAME already exists.
+   If INTERACTIVE is nonzero, ask the user whether to proceed,
+   and bypass the error if the user says to go ahead.
+   QUERYSTRING is a name for the action that is being considered
+   to alter the file.
+   *STATPTR is used to store the stat information if the file exists.
+   If the file does not exist, STATPTR->st_mode is set to 0.  */
+
 void
-barf_or_query_if_file_exists (absname, querystring, interactive)
+barf_or_query_if_file_exists (absname, querystring, interactive, statptr)
      Lisp_Object absname;
      unsigned char *querystring;
      int interactive;
+     struct stat *statptr;
 {
   register Lisp_Object tem;
   struct stat statbuf;
@@ -1804,6 +1823,13 @@ barf_or_query_if_file_exists (absname, querystring, interactive)
        Fsignal (Qfile_already_exists,
                 Fcons (build_string ("File already exists"),
                        Fcons (absname, Qnil)));
+      if (statptr)
+       *statptr = statbuf;
+    }
+  else
+    {
+      if (statptr)
+       statptr->st_mode = 0;
     }
   return;
 }
@@ -1823,7 +1849,7 @@ A prefix arg makes KEEP-TIME non-nil.")
 {
   int ifd, ofd, n;
   char buf[16 * 1024];
-  struct stat st;
+  struct stat st, out_st;
   Lisp_Object handler;
   struct gcpro gcpro1, gcpro2;
   int count = specpdl_ptr - specpdl;
@@ -1848,7 +1874,9 @@ A prefix arg makes KEEP-TIME non-nil.")
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
     barf_or_query_if_file_exists (newname, "copy to it",
-                                 INTEGERP (ok_if_already_exists));
+                                 INTEGERP (ok_if_already_exists), &out_st);
+  else if (stat (XSTRING (newname)->data, &out_st) < 0)
+    out_st.st_mode = 0;
 
   ifd = open (XSTRING (filename)->data, O_RDONLY);
   if (ifd < 0)
@@ -1860,6 +1888,16 @@ A prefix arg makes KEEP-TIME non-nil.")
      copyable by us. */
   input_file_statable_p = (fstat (ifd, &st) >= 0);
 
+#ifndef DOS_NT
+  if (out_st.st_mode != 0
+      && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
+    {
+      errno = 0;
+      report_file_error ("Input and output files are the same",
+                        Fcons (filename, Fcons (newname, Qnil)));
+    }
+#endif
+
 #if defined (S_ISREG) && defined (S_ISLNK)
   if (input_file_statable_p)
     {
@@ -1869,7 +1907,7 @@ A prefix arg makes KEEP-TIME non-nil.")
          /* Get a better looking error message. */
          errno = EISDIR;
 #endif /* EISDIR */
-       report_file_error ("Non-regular file", Fcons (filename, Qnil));
+         report_file_error ("Non-regular file", Fcons (filename, Qnil));
        }
     }
 #endif /* S_ISREG && S_ISLNK */
@@ -1886,7 +1924,7 @@ A prefix arg makes KEEP-TIME non-nil.")
 #endif /* not MSDOS */
 #endif /* VMS */
   if (ofd < 0)
-      report_file_error ("Opening output file", Fcons (newname, Qnil));
+    report_file_error ("Opening output file", Fcons (newname, Qnil));
 
   record_unwind_protect (close_file_unwind, make_number (ofd));
 
@@ -1894,7 +1932,7 @@ A prefix arg makes KEEP-TIME non-nil.")
   QUIT;
   while ((n = read (ifd, buf, sizeof buf)) > 0)
     if (write (ofd, buf, n) != n)
-       report_file_error ("I/O error", Fcons (newname, Qnil));
+      report_file_error ("I/O error", Fcons (newname, Qnil));
   immediate_quit = 0;
 
   /* Closing the output clobbers the file times on some systems.  */
@@ -1911,9 +1949,6 @@ A prefix arg makes KEEP-TIME non-nil.")
          if (set_file_times (XSTRING (newname)->data, atime, mtime))
            report_file_error ("I/O error", Fcons (newname, Qnil));
        }
-#ifdef APOLLO
-      if (!egetenv ("USE_DOMAIN_ACLS"))
-#endif
        chmod (XSTRING (newname)->data, st.st_mode & 07777);
     }
 
@@ -1925,7 +1960,7 @@ A prefix arg makes KEEP-TIME non-nil.")
   UNGCPRO;
   return Qnil;
 }
-
+\f
 DEFUN ("make-directory-internal", Fmake_directory_internal,
        Smake_directory_internal, 1, 1, 0,
   "Create a directory.  One argument, a file name string.")
@@ -1995,6 +2030,23 @@ If file has multiple names, it continues to exist with the other names.")
   return Qnil;
 }
 
+static Lisp_Object
+internal_delete_file_1 (ignore)
+     Lisp_Object ignore;
+{
+  return Qt;
+}
+
+/* Delete file FILENAME, returning 1 if successful and 0 if failed.  */
+
+int
+internal_delete_file (filename)
+     Lisp_Object filename;
+{
+  return NILP (internal_condition_case_1 (Fdelete_file, filename,
+                                         Qt, internal_delete_file_1));
+}
+\f
 DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
   "fRename file: \nFRename %s to file: \np",
   "Rename FILE as NEWNAME.  Both args strings.\n\
@@ -2030,7 +2082,7 @@ This is what happens in interactive use with M-x.")
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
     barf_or_query_if_file_exists (newname, "rename to it",
-                                 INTEGERP (ok_if_already_exists));
+                                 INTEGERP (ok_if_already_exists), 0);
 #ifndef BSD4_1
   if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
 #else
@@ -2100,10 +2152,17 @@ This is what happens in interactive use with M-x.")
     RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
                           newname, ok_if_already_exists));
 
+  /* If the new name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (newname, Qadd_name_to_file);
+  if (!NILP (handler))
+    RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
+                          newname, ok_if_already_exists));
+
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
     barf_or_query_if_file_exists (newname, "make it a new name",
-                                 INTEGERP (ok_if_already_exists));
+                                 INTEGERP (ok_if_already_exists), 0);
 #ifdef WINDOWSNT
   /* Windows does not support this operation.  */
   report_file_error ("Adding new name", Flist (2, &filename));
@@ -2160,10 +2219,17 @@ This happens for interactive use with M-x.")
     RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
                           linkname, ok_if_already_exists));
 
+  /* If the new link name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (linkname, Qmake_symbolic_link);
+  if (!NILP (handler))
+    RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
+                          linkname, ok_if_already_exists));
+
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
     barf_or_query_if_file_exists (linkname, "make it a link",
-                                 INTEGERP (ok_if_already_exists));
+                                 INTEGERP (ok_if_already_exists), 0);
   if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
     {
       /* If we didn't complain already, silently delete existing file.  */
@@ -2271,6 +2337,18 @@ static int
 check_executable (filename)
      char *filename;
 {
+#ifdef DOS_NT
+  int len = strlen (filename);
+  char *suffix;
+  struct stat st;
+  if (stat (filename, &st) < 0)
+    return 0;
+  return (S_ISREG (st.st_mode)
+         && len >= 5
+         && (stricmp ((suffix = filename + len-4), ".com") == 0
+             || stricmp (suffix, ".exe") == 0
+             || stricmp (suffix, ".bat") == 0));
+#else /* not DOS_NT */
 #ifdef HAVE_EACCESS
   return (eaccess (filename, 1) >= 0);
 #else
@@ -2279,6 +2357,7 @@ check_executable (filename)
      But Unix doesn't give us a right way to do it.  */
   return (access (filename, 1) >= 0);
 #endif
+#endif /* not DOS_NT */
 }
 
 /* Return nonzero if file FILENAME exists and can be written.  */
@@ -2287,6 +2366,12 @@ static int
 check_writable (filename)
      char *filename;
 {
+#ifdef MSDOS
+  struct stat st;
+  if (stat (filename, &st) < 0)
+    return 0;
+  return (st.st_mode & S_IWRITE || (st.st_mode & S_IFMT) == S_IFDIR);
+#else /* not MSDOS */
 #ifdef HAVE_EACCESS
   return (eaccess (filename, 2) >= 0);
 #else
@@ -2297,6 +2382,7 @@ check_writable (filename)
      but would lose for directories.  */
   return (access (filename, 2) >= 0);
 #endif
+#endif /* not MSDOS */
 }
 
 DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
@@ -2523,9 +2609,9 @@ This is the sort of file that holds an ordinary stream of data bytes.")
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (abspath, Qfile_directory_p);
+  handler = Ffind_file_name_handler (abspath, Qfile_regular_p);
   if (!NILP (handler))
-    return call2 (handler, Qfile_directory_p, abspath);
+    return call2 (handler, Qfile_regular_p, abspath);
 
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
@@ -2552,16 +2638,8 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
   if (stat (XSTRING (abspath)->data, &st) < 0)
     return Qnil;
 #ifdef DOS_NT
-  {
-    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;
-  }
+  if (check_executable (XSTRING (abspath)->data))
+    st.st_mode |= S_IEXEC;
 #endif /* DOS_NT */
 
   return make_number (st.st_mode & 07777);
@@ -2585,36 +2663,8 @@ Only the 12 low bits of MODE are used.")
   if (!NILP (handler))
     return call3 (handler, Qset_file_modes, abspath, mode);
 
-#ifndef APOLLO
   if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
     report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-#else /* APOLLO */
-  if (!egetenv ("USE_DOMAIN_ACLS"))
-    {
-      struct stat st;
-      struct timeval tvp[2];
-
-      /* chmod on apollo also change the file's modtime; need to save the
-        modtime and then restore it. */
-      if (stat (XSTRING (abspath)->data, &st) < 0)
-       {
-         report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-         return (Qnil);
-       }
-      if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
-       report_file_error ("Doing chmod", Fcons (abspath, Qnil));
-      /* reset the old accessed and modified times.  */
-      tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
-      tvp[0].tv_usec = 0;
-      tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
-      tvp[1].tv_usec = 0;
-      if (utimes (XSTRING (abspath)->data, tvp) < 0)
-       report_file_error ("Doing utimes", Fcons (abspath, Qnil));
-    }
-#endif /* APOLLO */
 
   return Qnil;
 }
@@ -2735,12 +2785,16 @@ and (2) it puts less data in the undo list.")
   int total;
   int not_regular = 0;
 
+  if (current_buffer->base_buffer && ! NILP (visit))
+    error ("Cannot do file visiting in an indirect buffer");
+
+  if (!NILP (current_buffer->read_only))
+    Fbarf_if_buffer_read_only ();
+
   val = Qnil;
   p = Qnil;
 
   GCPRO3 (filename, val, p);
-  if (!NILP (current_buffer->read_only))
-    Fbarf_if_buffer_read_only();
 
   CHECK_STRING (filename, 0);
   filename = Fexpand_file_name (filename, Qnil);
@@ -2917,6 +2971,10 @@ and (2) it puts less data in the undo list.")
             Otherwise loop around and scan the preceding bufferfull.  */
          if (bufpos != 0)
            break;
+         /* If display current starts at beginning of line,
+            keep it that way.  */
+         if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
+           XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
        }
       immediate_quit = 0;
 
@@ -3040,14 +3098,14 @@ and (2) it puts less data in the undo list.")
          current_buffer->filename = filename;
        }
 
-      current_buffer->save_modified = MODIFF;
+      SAVE_MODIFF = MODIFF;
       current_buffer->auto_save_modified = MODIFF;
       XSETFASTINT (current_buffer->save_length, Z - BEG);
 #ifdef CLASH_DETECTION
       if (NILP (handler))
        {
-         if (!NILP (current_buffer->filename))
-           unlock_file (current_buffer->filename);
+         if (!NILP (current_buffer->file_truename))
+           unlock_file (current_buffer->file_truename);
          unlock_file (filename);
        }
 #endif /* CLASH_DETECTION */
@@ -3061,6 +3119,15 @@ and (2) it puts less data in the undo list.")
        report_file_error ("Opening input file", Fcons (filename, Qnil));
     }
 
+  /* Decode file format */
+  if (inserted > 0)
+    {
+      insval = call3 (Qformat_decode, 
+                     Qnil, make_number (inserted), visit);
+      CHECK_NUMBER (insval, 0);
+      inserted = XFASTINT (insval);
+    }
+
   if (inserted > 0 && NILP (visit) && total > 0)
     signal_after_change (point, 0, inserted);
   
@@ -3107,7 +3174,7 @@ build_annotations_unwind (buf)
   return Qnil;
 }
 
-DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
+DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
   "r\nFWrite region to file: ",
   "Write current region into specified file.\n\
 When called from a program, takes three arguments:\n\
@@ -3122,10 +3189,12 @@ If VISIT is a string, it is a second file name;\n\
   VISIT is also the file name to lock and unlock for clash detection.\n\
 If VISIT is neither t nor nil nor a string,\n\
   that means do not print the \"Wrote file\" message.\n\
+The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
+  use for locking and unlocking, overriding FILENAME and VISIT.\n\
 Kludgy feature: if START is a string, then that string is written\n\
 to the file, instead of any buffer contents, and END is ignored.")
-  (start, end, filename, append, visit)
-     Lisp_Object start, end, filename, append, visit;
+  (start, end, filename, append, visit, lockname)
+     Lisp_Object start, end, filename, append, visit, lockname;
 {
   register int desc;
   int failure;
@@ -3142,17 +3211,20 @@ to the file, instead of any buffer contents, and END is ignored.")
   Lisp_Object visit_file;
   Lisp_Object annotations;
   int visiting, quietly;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   struct buffer *given_buffer;
 #ifdef DOS_NT
   int buffer_file_type
     = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
 #endif /* DOS_NT */
 
+  if (current_buffer->base_buffer && ! NILP (visit))
+    error ("Cannot do file visiting in an indirect buffer");
+
   if (!NILP (start) && !STRINGP (start))
     validate_region (&start, &end);
 
-  GCPRO2 (filename, visit);
+  GCPRO3 (filename, visit, lockname);
   filename = Fexpand_file_name (filename, Qnil);
   if (STRINGP (visit))
     visit_file = Fexpand_file_name (visit, Qnil);
@@ -3165,7 +3237,10 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   annotations = Qnil;
 
-  GCPRO4 (start, filename, annotations, visit_file);
+  if (NILP (lockname))
+    lockname = visit_file;
+
+  GCPRO5 (start, filename, annotations, visit_file, lockname);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -3182,7 +3257,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
       if (visiting)
        {
-         current_buffer->save_modified = MODIFF;
+         SAVE_MODIFF = MODIFF;
          XSETFASTINT (current_buffer->save_length, Z - BEG);
          current_buffer->filename = visit_file;
        }
@@ -3210,7 +3285,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
-    lock_file (visit_file);
+    lock_file (lockname);
 #endif /* CLASH_DETECTION */
 
   fn = XSTRING (filename)->data;
@@ -3284,7 +3359,7 @@ to the file, instead of any buffer contents, and END is ignored.")
     {
 #ifdef CLASH_DETECTION
       save_errno = errno;
-      if (!auto_saving) unlock_file (visit_file);
+      if (!auto_saving) unlock_file (lockname);
       errno = save_errno;
 #endif /* CLASH_DETECTION */
       report_file_error ("Opening output file", Fcons (filename, Qnil));
@@ -3296,7 +3371,7 @@ to the file, instead of any buffer contents, and END is ignored.")
     if (lseek (desc, 0, 2) < 0)
       {
 #ifdef CLASH_DETECTION
-       if (!auto_saving) unlock_file (visit_file);
+       if (!auto_saving) unlock_file (lockname);
 #endif /* CLASH_DETECTION */
        report_file_error ("Lseek error", Fcons (filename, Qnil));
       }
@@ -3369,7 +3444,11 @@ to the file, instead of any buffer contents, and END is ignored.")
   /* mib says that closing the file will try to write as fast as NFS can do
      it, and that means the fsync here is not crucial for autosave files.  */
   if (!auto_saving && fsync (desc) < 0)
-    failure = 1, save_errno = errno;
+    {
+      /* If fsync fails with EINTR, don't treat that as serious.  */
+      if (errno != EINTR)
+       failure = 1, save_errno = errno;
+    }
 #endif
 
   /* Spurious "file has changed on disk" warnings have been 
@@ -3415,7 +3494,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
 #ifdef CLASH_DETECTION
   if (!auto_saving)
-    unlock_file (visit_file);
+    unlock_file (lockname);
 #endif /* CLASH_DETECTION */
 
   /* Do this before reporting IO error
@@ -3429,7 +3508,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   if (visiting)
     {
-      current_buffer->save_modified = MODIFF;
+      SAVE_MODIFF = MODIFF;
       XSETFASTINT (current_buffer->save_length, Z - BEG);
       current_buffer->filename = visit_file;
       update_mode_lines++;
@@ -3492,6 +3571,27 @@ build_annotations (start, end)
       annotations = merge (annotations, res, Qcar_less_than_car);
       p = Fcdr (p);
     }
+
+  /* Now do the same for annotation functions implied by the file-format */
+  if (auto_saving && (!EQ (Vauto_save_file_format, Qt)))
+    p = Vauto_save_file_format;
+  else
+    p = current_buffer->file_format;
+  while (!NILP (p))
+    {
+      struct buffer *given_buffer = current_buffer;
+      Vwrite_region_annotations_so_far = annotations;
+      res = call3 (Qformat_annotate_function, Fcar (p), start, end);
+      if (current_buffer != given_buffer)
+       {
+         start = BEGV;
+         end = ZV;
+         annotations = Qnil;
+       }
+      Flength (res);
+      annotations = merge (annotations, res, Qcar_less_than_car);
+      p = Fcdr (p);
+    }
   UNGCPRO;
   return annotations;
 }
@@ -3634,7 +3734,7 @@ The value is a list of the form (HIGH . LOW), like the time values\n\
 that `file-attributes' returns.")
   ()
 {
-  return long_to_cons (current_buffer->modtime);
+  return long_to_cons ((unsigned long) current_buffer->modtime);
 }
 
 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
@@ -3700,13 +3800,14 @@ auto_save_1 ()
   return
     Fwrite_region (Qnil, Qnil,
                   current_buffer->auto_save_file_name,
-                  Qnil, Qlambda);
+                  Qnil, Qlambda, Qnil);
 }
 
 static Lisp_Object
 do_auto_save_unwind (desc)  /* used as unwind-protect function */
      Lisp_Object desc;
 {
+  auto_saving = 0;
   close (XINT (desc));
   return Qnil;
 }
@@ -3744,7 +3845,6 @@ Non-nil second argument means save only current buffer.")
   /* No GCPRO needed, because (when it matters) all Lisp_Object variables
      point to non-strings reached from Vbuffer_alist.  */
 
-  auto_saving = 1;
   if (minibuf_level)
     no_message = Qt;
 
@@ -3753,38 +3853,49 @@ Non-nil second argument means save only current buffer.")
 
   if (STRINGP (Vauto_save_list_file_name))
     {
+      Lisp_Object listfile;
+      listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
 #ifdef DOS_NT
-      listdesc = open (XSTRING (Vauto_save_list_file_name)->data, 
+      listdesc = open (XSTRING (listfile)->data, 
                       O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
                       S_IREAD | S_IWRITE);
 #else  /* not DOS_NT */
-      listdesc = creat (XSTRING (Vauto_save_list_file_name)->data, 0666);
+      listdesc = creat (XSTRING (listfile)->data, 0666);
 #endif /* not DOS_NT */
     }
   else
     listdesc = -1;
   
-  /* Arrange to close that file whether or not we get an error.  */
+  /* Arrange to close that file whether or not we get an error.
+     Also reset auto_saving to 0.  */
   if (listdesc >= 0)
     record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
 
+  auto_saving = 1;
+
   /* First, save all files which don't have handlers.  If Emacs is
      crashing, the handlers may tweak what is causing Emacs to crash
      in the first place, and it would be a shame if Emacs failed to
      autosave perfectly ordinary files because it couldn't handle some
      ange-ftp'd file.  */
   for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
-    for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
-        tail = XCONS (tail)->cdr)
+    for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
       {
        buf = XCONS (XCONS (tail)->car)->cdr;
        b = XBUFFER (buf);
       
        /* Record all the buffers that have auto save mode
-          in the special file that lists them.  */
+          in the special file that lists them.  For each of these buffers,
+          Record visited name (if any) and auto save name.  */
        if (STRINGP (b->auto_save_file_name)
            && listdesc >= 0 && do_handled_files == 0)
          {
+           if (!NILP (b->filename))
+             {
+               write (listdesc, XSTRING (b->filename)->data,
+                      XSTRING (b->filename)->size);
+             }
+           write (listdesc, "\n", 1);
            write (listdesc, XSTRING (b->auto_save_file_name)->data,
                   XSTRING (b->auto_save_file_name)->size);
            write (listdesc, "\n", 1);
@@ -3794,11 +3905,16 @@ Non-nil second argument means save only current buffer.")
            && b != current_buffer)
          continue;
 
+       /* Don't auto-save indirect buffers.
+          The base buffer takes care of it.  */
+       if (b->base_buffer)
+         continue;
+
        /* Check for auto save enabled
           and file changed since last auto save
           and file changed since last real save.  */
        if (STRINGP (b->auto_save_file_name)
-           && b->save_modified < BUF_MODIFF (b)
+           && BUF_SAVE_MODIFF (b) < 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
@@ -3864,7 +3980,6 @@ Non-nil second argument means save only current buffer.")
 
   Vquit_flag = oquit;
 
-  auto_saving = 0;
   unbind_to (count, Qnil);
   return Qnil;
 }
@@ -3895,7 +4010,7 @@ DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
   "Return t if buffer has been auto-saved since last read in or saved.")
   ()
 {
-  return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
+  return (SAVE_MODIFF < current_buffer->auto_save_modified) ? Qt : Qnil;
 }
 \f
 /* Reading and completing file names */
@@ -4165,6 +4280,7 @@ DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
 syms_of_fileio ()
 {
   Qexpand_file_name = intern ("expand-file-name");
+  Qsubstitute_in_file_name = intern ("substitute-in-file-name");
   Qdirectory_file_name = intern ("directory-file-name");
   Qfile_name_directory = intern ("file-name-directory");
   Qfile_name_nondirectory = intern ("file-name-nondirectory");
@@ -4183,6 +4299,7 @@ syms_of_fileio ()
   Qfile_symlink_p = intern ("file-symlink-p");
   Qfile_writable_p = intern ("file-writable-p");
   Qfile_directory_p = intern ("file-directory-p");
+  Qfile_regular_p = intern ("file-regular-p");
   Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
   Qfile_modes = intern ("file-modes");
   Qset_file_modes = intern ("set-file-modes");
@@ -4191,9 +4308,9 @@ syms_of_fileio ()
   Qwrite_region = intern ("write-region");
   Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
   Qset_visited_file_modtime = intern ("set-visited-file-modtime");
-  Qsubstitute_in_file_name = intern ("substitute-in-file-name");
 
   staticpro (&Qexpand_file_name);
+  staticpro (&Qsubstitute_in_file_name);
   staticpro (&Qdirectory_file_name);
   staticpro (&Qfile_name_directory);
   staticpro (&Qfile_name_nondirectory);
@@ -4212,6 +4329,7 @@ syms_of_fileio ()
   staticpro (&Qfile_symlink_p);
   staticpro (&Qfile_writable_p);
   staticpro (&Qfile_directory_p);
+  staticpro (&Qfile_regular_p);
   staticpro (&Qfile_accessible_directory_p);
   staticpro (&Qfile_modes);
   staticpro (&Qset_file_modes);
@@ -4219,7 +4337,6 @@ syms_of_fileio ()
   staticpro (&Qinsert_file_contents);
   staticpro (&Qwrite_region);
   staticpro (&Qverify_visited_file_modtime);
-  staticpro (&Qsubstitute_in_file_name);
 
   Qfile_name_history = intern ("file-name-history");
   Fset (Qfile_name_history, Qnil);
@@ -4235,6 +4352,18 @@ syms_of_fileio ()
   staticpro (&Qfind_buffer_file_type);
 #endif /* DOS_NT */
 
+  DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format,
+    "*Format in which to write auto-save files.\n\
+Should be a list of symbols naming formats that are defined in `format-alist'.\n\
+If it is t, which is the default, auto-save files are written in the\n\
+same format as a regular save would use.");
+  Vauto_save_file_format = Qt;
+
+  Qformat_decode = intern ("format-decode");
+  staticpro (&Qformat_decode);
+  Qformat_annotate_function = intern ("format-annotate-function");
+  staticpro (&Qformat_annotate_function);
+       
   Qcar_less_than_car = intern ("car-less-than-car");
   staticpro (&Qcar_less_than_car);