]> code.delx.au - gnu-emacs/blobdiff - src/fileio.c
*** empty log message ***
[gnu-emacs] / src / fileio.c
index d1e80d6c34b653b02c63670ca882966c51a4c9da..7f73a55bce906abc742a6fc75bf176634b62e9c4 100644 (file)
@@ -1,6 +1,6 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985,86,87,88,93,94,95,96,97,98,99,2000, 2001
-     Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1996, 1997, 1998,
+     1999, 2000, 2001, 2003, 2004  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -134,6 +134,7 @@ extern int errno;
 
 #include "commands.h"
 extern int use_dialog_box;
+extern int use_file_dialog;
 
 #ifndef O_WRONLY
 #define O_WRONLY 1
@@ -147,6 +148,10 @@ extern int use_dialog_box;
 #  define lstat stat
 #endif
 
+#ifndef FILE_SYSTEM_CASE
+#define FILE_SYSTEM_CASE(filename)  (filename)
+#endif
+
 /* Nonzero during writing of auto-save files */
 int auto_saving;
 
@@ -154,6 +159,13 @@ int auto_saving;
    a new file with the same mode as the original */
 int auto_save_mode_bits;
 
+/* The symbol bound to coding-system-for-read when
+   insert-file-contents is called for recovering a file.  This is not
+   an actual coding system name, but just an indicator to tell
+   insert-file-contents to use `emacs-mule' with a special flag for
+   auto saving and recovering a file.  */
+Lisp_Object Qauto_save_coding;
+
 /* Coding system for file names, or nil if none.  */
 Lisp_Object Vfile_name_coding_system;
 
@@ -165,9 +177,6 @@ Lisp_Object Vdefault_file_name_coding_system;
    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;
 
@@ -177,8 +186,13 @@ Lisp_Object Vset_auto_coding_function;
 /* Functions to be called to process text properties in inserted file.  */
 Lisp_Object Vafter_insert_file_functions;
 
+/* Lisp function for setting buffer-file-coding-system and the
+   multibyteness of the current buffer after inserting a file.  */
+Lisp_Object Qafter_insert_file_set_coding;
+
 /* Functions to be called to create text property annotations for file.  */
 Lisp_Object Vwrite_region_annotate_functions;
+Lisp_Object Qwrite_region_annotate_functions;
 
 /* During build_annotations, each time an annotation function is called,
    this holds the annotations made by the previous functions.  */
@@ -193,6 +207,9 @@ Lisp_Object Vread_file_name_function;
 /* Current predicate used by read_file_name_internal.  */
 Lisp_Object Vread_file_name_predicate;
 
+/* Nonzero means completion ignores case when reading file name.  */
+int read_file_name_completion_ignore_case;
+
 /* Nonzero means, when reading a filename in the minibuffer,
  start out by inserting the default directory into the minibuffer. */
 int insert_default_directory;
@@ -215,6 +232,8 @@ extern int minibuf_level;
 
 extern int minibuffer_auto_raise;
 
+extern int history_delete_duplicates;
+
 /* These variables describe handlers that have "already" had a chance
    to handle the current operation.
 
@@ -310,6 +329,7 @@ Lisp_Object Qfile_regular_p;
 Lisp_Object Qfile_accessible_directory_p;
 Lisp_Object Qfile_modes;
 Lisp_Object Qset_file_modes;
+Lisp_Object Qset_file_times;
 Lisp_Object Qfile_newer_than_file_p;
 Lisp_Object Qinsert_file_contents;
 Lisp_Object Qwrite_region;
@@ -397,9 +417,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_name_directory, filename);
 
-#ifdef FILE_SYSTEM_CASE
   filename = FILE_SYSTEM_CASE (filename);
-#endif
   beg = SDATA (filename);
 #ifdef DOS_NT
   beg = strcpy (alloca (strlen (beg) + 1), beg);
@@ -869,7 +887,7 @@ make_temp_name (prefix, base64_p)
      int base64_p;
 {
   Lisp_Object val;
-  int len;
+  int len, clen;
   int pid;
   unsigned char *p, *data;
   char pidbuf[20];
@@ -904,8 +922,10 @@ make_temp_name (prefix, base64_p)
 #endif
     }
 
-  len = SCHARS (prefix);
-  val = make_uninit_string (len + 3 + pidlen);
+  len = SBYTES (prefix); clen = SCHARS (prefix);
+  val = make_uninit_multibyte_string (clen + 3 + pidlen, len + 3 + pidlen);
+  if (!STRING_MULTIBYTE (prefix))
+    STRING_SET_UNIBYTE (val);
   data = SDATA (val);
   bcopy(SDATA (prefix), data, len);
   p = data + len;
@@ -1102,14 +1122,7 @@ See also the function `substitute-in-file-name'.  */)
       UNGCPRO;
     }
 
-#ifdef VMS
-  /* Filenames on VMS are always upper case.  */
-  name = Fupcase (name);
-#endif
-#ifdef FILE_SYSTEM_CASE
   name = FILE_SYSTEM_CASE (name);
-#endif
-
   nm = SDATA (name);
 
 #ifdef DOS_NT
@@ -1209,23 +1222,23 @@ See also the function `substitute-in-file-name'.  */)
            slash = p;
          }
          if (p[0] == '-')
-#ifndef VMS4_4
-           /* VMS pre V4.4,convert '-'s in filenames. */
+#ifdef NO_HYPHENS_IN_FILENAMES
            if (lbrack == rbrack)
              {
-               if (dots < 2)   /* this is to allow negative version numbers */
+                /* Avoid clobbering negative version numbers.  */
+                if (dots < 2)
                  p[0] = '_';
              }
            else
-#endif /* VMS4_4 */
+#endif /* NO_HYPHENS_IN_FILENAMES */
              if (lbrack > rbrack &&
                  ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
                   (p[1] == '.' || p[1] == ']' || p[1] == '>')))
                lose = 1;
-#ifndef VMS4_4
+#ifdef NO_HYPHENS_IN_FILENAMES
              else
                p[0] = '_';
-#endif /* VMS4_4 */
+#endif /* NO_HYPHENS_IN_FILENAMES */
          /* count open brackets, reset close bracket pointer */
          if (p[0] == '[' || p[0] == '<')
            lbrack++, brack = 0;
@@ -1605,12 +1618,12 @@ See also the function `substitute-in-file-name'.  */)
        }
       else
        {
-#ifndef VMS4_4
+#ifdef NO_HYPHENS_IN_FILENAMES
          if (*p == '-' &&
              o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
              p[1] != ']' && p[1] != '>' && p[1] != '.')
            *p = '_';
-#endif /* VMS4_4 */
+#endif /* NO_HYPHENS_IN_FILENAMES */
          *o++ = *p++;
        }
 #else /* not VMS */
@@ -2335,7 +2348,7 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
 
   /* stat is a good way to tell whether the file exists,
      regardless of what access permissions it has.  */
-  if (stat (SDATA (encoded_filename), &statbuf) >= 0)
+  if (lstat (SDATA (encoded_filename), &statbuf) >= 0)
     {
       if (! interactive)
        Fsignal (Qfile_already_exists,
@@ -2372,7 +2385,8 @@ Signals a `file-already-exists' error if file NEWNAME already exists,
 unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.
 A number as third arg means request confirmation if NEWNAME already exists.
 This is what happens in interactive use with M-x.
-Fourth arg KEEP-TIME non-nil means give the new file the same
+Always sets the file modes of the output file to match the input file.
+Fourth arg KEEP-TIME non-nil means give the output file the same
 last-modified time as the old one.  (This works on only some systems.)
 A prefix arg makes KEEP-TIME non-nil.  */)
      (file, newname, ok_if_already_exists, keep_time)
@@ -2393,7 +2407,7 @@ A prefix arg makes KEEP-TIME non-nil.  */)
   CHECK_STRING (newname);
 
   if (!NILP (Ffile_directory_p (newname)))
-    newname = Fexpand_file_name (file, newname);
+    newname = Fexpand_file_name (Ffile_name_nondirectory (file), newname);
   else
     newname = Fexpand_file_name (newname, Qnil);
 
@@ -2618,7 +2632,8 @@ If file has multiple names, it continues to exist with the other names.  */)
   struct gcpro gcpro1;
 
   GCPRO1 (filename);
-  if (!NILP (Ffile_directory_p (filename)))
+  if (!NILP (Ffile_directory_p (filename))
+      && NILP (Ffile_symlink_p (filename)))
     Fsignal (Qfile_error,
             Fcons (build_string ("Removing old name: is a directory"),
                    Fcons (filename, Qnil)));
@@ -2668,11 +2683,11 @@ This is what happens in interactive use with M-x.  */)
   Lisp_Object args[2];
 #endif
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
-  Lisp_Object encoded_file, encoded_newname;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
+  Lisp_Object encoded_file, encoded_newname, symlink_target;
 
-  encoded_file = encoded_newname = Qnil;
-  GCPRO4 (file, newname, encoded_file, encoded_newname);
+  symlink_target = encoded_file = encoded_newname = Qnil;
+  GCPRO5 (file, newname, encoded_file, encoded_newname, symlink_target);
   CHECK_STRING (file);
   CHECK_STRING (newname);
   file = Fexpand_file_name (file, Qnil);
@@ -2709,10 +2724,17 @@ This is what happens in interactive use with M-x.  */)
     {
       if (errno == EXDEV)
        {
-         Fcopy_file (file, newname,
-                     /* We have already prompted if it was an integer,
-                        so don't have copy-file prompt again.  */
-                     NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
+#ifdef S_IFLNK
+          symlink_target = Ffile_symlink_p (file);
+          if (! NILP (symlink_target))
+            Fmake_symbolic_link (symlink_target, newname,
+                                 NILP (ok_if_already_exists) ? Qnil : Qt);
+          else
+#endif
+            Fcopy_file (file, newname,
+                        /* We have already prompted if it was an integer,
+                           so don't have copy-file prompt again.  */
+                        NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
          Fdelete_file (file);
        }
       else
@@ -3182,16 +3204,11 @@ If there is no error, we return nil.  */)
 \f
 DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
        doc: /* Return non-nil if file FILENAME is the name of a symbolic link.
-The value is the name of the file to which it is linked.
+The value is the link target, as a string.
 Otherwise returns nil.  */)
      (filename)
      Lisp_Object filename;
 {
-#ifdef S_IFLNK
-  char *buf;
-  int bufsize;
-  int valsize;
-  Lisp_Object val;
   Lisp_Object handler;
 
   CHECK_STRING (filename);
@@ -3203,6 +3220,13 @@ Otherwise returns nil.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_symlink_p, filename);
 
+#ifdef S_IFLNK
+  {
+  char *buf;
+  int bufsize;
+  int valsize;
+  Lisp_Object val;
+
   filename = ENCODE_FILE (filename);
 
   bufsize = 50;
@@ -3237,6 +3261,7 @@ Otherwise returns nil.  */)
   xfree (buf);
   val = DECODE_FILE (val);
   return val;
+  }
 #else /* not S_IFLNK */
   return Qnil;
 #endif /* not S_IFLNK */
@@ -3338,7 +3363,8 @@ This is the sort of file that holds an ordinary stream of data bytes.  */)
 }
 \f
 DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
-       doc: /* Return mode bits of file named FILENAME, as an integer.  */)
+       doc: /* Return mode bits of file named FILENAME, as an integer.
+Return nil, if file does not exist or is not accessible.  */)
      (filename)
      Lisp_Object filename;
 {
@@ -3420,7 +3446,59 @@ The value is an integer.  */)
   XSETINT (value, (~ realmask) & 0777);
   return value;
 }
+\f
+extern int lisp_time_argument P_ ((Lisp_Object, time_t *, int *));
+
+DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 2, 0,
+       doc: /* Set times of file FILENAME to TIME.
+Set both access and modification times.
+Return t on success, else nil.
+Use the current time if TIME is nil.  TIME is in the format of
+`current-time'. */)
+  (filename, time)
+     Lisp_Object filename, time;
+{
+  Lisp_Object absname, encoded_absname;
+  Lisp_Object handler;
+  time_t sec;
+  int usec;
 
+  if (! lisp_time_argument (time, &sec, &usec))
+    error ("Invalid time specification");
+
+  absname = Fexpand_file_name (filename, current_buffer->directory);
+
+  /* If the file name has special constructs in it,
+     call the corresponding file handler.  */
+  handler = Ffind_file_name_handler (absname, Qset_file_times);
+  if (!NILP (handler))
+    return call3 (handler, Qset_file_times, absname, time);
+
+  encoded_absname = ENCODE_FILE (absname);
+
+  {
+    EMACS_TIME t;
+
+    EMACS_SET_SECS (t, sec);
+    EMACS_SET_USECS (t, usec);
+
+    if (set_file_times (SDATA (encoded_absname), t, t))
+      {
+#ifdef DOS_NT
+        struct stat st;
+
+        /* Setting times on a directory always fails.  */
+        if (stat (SDATA (encoded_absname), &st) == 0
+            && (st.st_mode & S_IFMT) == S_IFDIR)
+          return Qnil;
+#endif
+        report_file_error ("Setting file times", Fcons (absname, Qnil));
+        return Qnil;
+      }
+  }
+
+  return Qt;
+}
 \f
 #ifdef __NetBSD__
 #define unix 42
@@ -3755,7 +3833,20 @@ actually used.  */)
        }
     }
 
-  if (BEG < Z)
+  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;
+    }
+  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
@@ -3765,10 +3856,6 @@ actually used.  */)
 
       if (!NILP (Vcoding_system_for_read))
        val = Vcoding_system_for_read;
-      else if (! NILP (replace))
-       /* In REPLACE mode, we can use the same coding system
-          that was used to visit the file.  */
-       val = current_buffer->buffer_file_coding_system;
       else
        {
          /* Don't try looking inside a file for a coding system
@@ -3810,12 +3897,13 @@ actually used.  */)
                  buffer = Fget_buffer_create (build_string (" *code-converting-work*"));
                  buf = XBUFFER (buffer);
 
+                 delete_all_overlays (buf);
                  buf->directory = current_buffer->directory;
                  buf->read_only = Qnil;
                  buf->filename = Qnil;
                  buf->undo_list = Qt;
-                 buf->overlays_before = Qnil;
-                 buf->overlays_after = Qnil;
+                 eassert (buf->overlays_before == NULL);
+                 eassert (buf->overlays_after == NULL);
 
                  set_buffer_internal (buf);
                  Ferase_buffer ();
@@ -4166,7 +4254,7 @@ actually used.  */)
       if (how_much < 0)
        {
          xfree (conversion_buffer);
-
+         coding_free_composition_data (&coding);
          if (how_much == -1)
            error ("IO error reading %s: %s",
                   SDATA (orig_filename), emacs_strerror (errno));
@@ -4188,6 +4276,7 @@ actually used.  */)
       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.  */
@@ -4233,7 +4322,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.  */
-      inserted -= (Z_BYTE - same_at_end) + (same_at_start - BEG_BYTE);
+      inserted -= (ZV_BYTE - same_at_end) + (same_at_start - BEGV_BYTE);
 
       if (same_at_end != same_at_start)
        {
@@ -4247,7 +4336,7 @@ actually used.  */)
        }
       /* Insert from the file at the proper position.  */
       SET_PT_BOTH (temp, same_at_start);
-      insert_1 (conversion_buffer + same_at_start - BEG_BYTE, inserted,
+      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 ());
@@ -4540,6 +4629,20 @@ actually used.  */)
                        Fcons (orig_filename, Qnil)));
     }
 
+  if (set_coding_system)
+    Vlast_coding_system_used = coding.symbol;
+
+  if (! NILP (Ffboundp (Qafter_insert_file_set_coding)))
+    {
+      insval = call2 (Qafter_insert_file_set_coding, make_number (inserted),
+                     visit);
+      if (! NILP (insval))
+       {
+         CHECK_NUMBER (insval);
+         inserted = XFASTINT (insval);
+       }
+    }
+
   /* Decode file format */
   if (inserted > 0)
     {
@@ -4563,9 +4666,6 @@ actually used.  */)
        current_buffer->undo_list = empty_undo_list_p ? Qnil : Qt;
     }
 
-  if (set_coding_system)
-    Vlast_coding_system_used = coding.symbol;
-
   /* Call after-change hooks for the inserted text, aside from the case
      of normal visiting (not with REPLACE), which is done in a new buffer
      "before" the buffer is changed.  */
@@ -4643,8 +4743,17 @@ choose_write_coding_system (start, end, filename,
 {
   Lisp_Object val;
 
-  if (auto_saving)
-    val = 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;
+      goto done_setup_coding;
+    }
   else if (!NILP (Vcoding_system_for_write))
     {
       val = Vcoding_system_for_write;
@@ -4752,7 +4861,7 @@ instead of any buffer contents; END is ignored.
 Optional fourth argument APPEND if non-nil means
   append to existing file contents (if any).  If it is an integer,
   seek to that offset in the file before writing.
-Optional fifth argument VISIT if t means
+Optional fifth argument VISIT, if t or a string, means
   set the last-save-file-modtime of buffer to this file's modtime
   and mark buffer not modified.
 If VISIT is a string, it is a second file name;
@@ -4846,11 +4955,14 @@ This does code conversion according to the value of
       return val;
     }
 
+  record_unwind_protect (save_restriction_restore, save_restriction_save ());
+
   /* Special kludge to simplify auto-saving.  */
   if (NILP (start))
     {
       XSETFASTINT (start, BEG);
       XSETFASTINT (end, Z);
+      Fwiden ();
     }
 
   record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
@@ -5169,10 +5281,22 @@ This does code conversion according to the value of
       update_mode_lines++;
     }
   else if (quietly)
-    return Qnil;
+    {
+      if (auto_saving
+         && ! NILP (Fstring_equal (current_buffer->filename,
+                                   current_buffer->auto_save_file_name)))
+       SAVE_MODIFF = MODIFF;
+
+      return Qnil;
+    }
 
   if (!auto_saving)
-    message_with_string ("Wrote %s", visit_file, 1);
+    message_with_string ((INTEGERP (append)
+                         ? "Updated %s"
+                         : ! NILP (append)
+                         ? "Added to %s"
+                         : "Wrote %s"),
+                        visit_file, 1);
 
   return Qnil;
 }
@@ -5203,7 +5327,7 @@ build_annotations (start, end)
   Lisp_Object p, res;
   struct gcpro gcpro1, gcpro2;
   Lisp_Object original_buffer;
-  int i;
+  int i, used_global = 0;
 
   XSETBUFFER (original_buffer, current_buffer);
 
@@ -5213,6 +5337,15 @@ build_annotations (start, end)
   while (CONSP (p))
     {
       struct buffer *given_buffer = current_buffer;
+      if (EQ (Qt, XCAR (p)) && !used_global)
+       { /* Use the global value of the hook.  */
+         Lisp_Object arg[2];
+         used_global = 1;
+         arg[0] = Fdefault_value (Qwrite_region_annotate_functions);
+         arg[1] = XCDR (p);
+         p = Fappend (2, arg);
+         continue;
+       }
       Vwrite_region_annotations_so_far = annotations;
       res = call2 (XCAR (p), start, end);
       /* If the function makes a different buffer current,
@@ -5232,8 +5365,8 @@ build_annotations (start, end)
     }
 
   /* 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;
+  if (auto_saving && (!EQ (current_buffer->auto_save_file_format, Qt)))
+    p = current_buffer->auto_save_file_format;
   else
     p = current_buffer->file_format;
   for (i = 0; CONSP (p); p = XCDR (p), ++i)
@@ -5434,7 +5567,8 @@ e_write (desc, string, start, end, coding)
 DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
        Sverify_visited_file_modtime, 1, 1, 0,
        doc: /* Return t if last mod time of BUF's visited file matches what BUF records.
-This means that the file has not been changed since it was visited or saved.  */)
+This means that the file has not been changed since it was visited or saved.
+See Info node `(elisp)Modification Time' for more details.  */)
      (buf)
      Lisp_Object buf;
 {
@@ -5489,11 +5623,17 @@ Next attempt to save will certainly not complain of a discrepancy.  */)
 DEFUN ("visited-file-modtime", Fvisited_file_modtime,
        Svisited_file_modtime, 0, 0, 0,
        doc: /* Return the current buffer's recorded visited file modification time.
-The value is a list of the form (HIGH . LOW), like the time values
-that `file-attributes' returns.  */)
+The value is a list of the form (HIGH LOW), like the time values
+that `file-attributes' returns.  If the current buffer has no recorded
+file modification time, this function returns 0.
+See Info node `(elisp)Modification Time' for more details.  */)
      ()
 {
-  return long_to_cons ((unsigned long) current_buffer->modtime);
+  Lisp_Object tcons;
+  tcons = long_to_cons ((unsigned long) current_buffer->modtime);
+  if (CONSP (tcons))
+    return list2 (XCAR (tcons), XCDR (tcons));
+  return tcons;
 }
 
 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
@@ -5567,14 +5707,21 @@ Lisp_Object
 auto_save_1 ()
 {
   struct stat st;
+  Lisp_Object modes;
+
+  auto_save_mode_bits = 0666;
 
   /* Get visited file's mode to become the auto save file's mode.  */
-  if (! NILP (current_buffer->filename)
-      && stat (SDATA (current_buffer->filename), &st) >= 0)
-    /* But make sure we can overwrite it later!  */
-    auto_save_mode_bits = st.st_mode | 0600;
-  else
-    auto_save_mode_bits = 0666;
+  if (! NILP (current_buffer->filename))
+    {
+      if (stat (SDATA (current_buffer->filename), &st) >= 0)
+       /* But make sure we can overwrite it later!  */
+       auto_save_mode_bits = st.st_mode | 0600;
+      else if ((modes = Ffile_modes (current_buffer->filename),
+               INTEGERP (modes)))
+       /* Remote files don't cooperate with stat.  */
+       auto_save_mode_bits = XINT (modes) | 0600;
+    }
 
   return
     Fwrite_region (Qnil, Qnil,
@@ -5710,11 +5857,14 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
   minibuffer_auto_raise = 0;
   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.  */
+  /* On first pass, save all files that don't have handlers.
+     On second pass, save all files that do 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; GC_CONSP (tail); tail = XCDR (tail))
       {
@@ -6017,27 +6167,53 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte
   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.
+The return value is only relevant for a call to `read-file-name' that happens
+before any other event (mouse or keypress) is handeled.  */)
+  ()
+{
+#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) || defined (HAVE_CARBON)
+  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+      && use_dialog_box
+      && use_file_dialog
+      && have_menus_p ())
+    return Qt;
+#endif
+  return Qnil;
+}
+
 DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 6, 0,
        doc: /* Read file name, prompting with PROMPT and completing in directory DIR.
 Value is not expanded---you must call `expand-file-name' yourself.
-Default name to DEFAULT-FILENAME if user enters a null string.
+Default name to DEFAULT-FILENAME if user exits the minibuffer with
+the same non-empty string that was inserted by this function.
  (If DEFAULT-FILENAME is omitted, the visited file name is used,
   except that if INITIAL is specified, that combined with DIR is used.)
+If the user exits with an empty minibuffer, this function returns
+an empty string.  (This can only happen if the user erased the
+pre-inserted contents or if `insert-default-directory' is nil.)
 Fourth arg MUSTMATCH non-nil means require existing file's name.
  Non-nil and non-t means also require confirmation after completion.
 Fifth arg INITIAL specifies text to start with.
-If optional sixth arg PREDICATE is non-nil, possible completions and the
-resulting file name must satisfy (funcall PREDICATE NAME).
-DIR defaults to current buffer's directory default.
+If optional sixth arg PREDICATE is non-nil, possible completions and
+the resulting file name must satisfy (funcall PREDICATE NAME).
+DIR should be an absolute directory name.  It defaults to the value of
+`default-directory'.
 
 If this command was invoked with the mouse, use a file dialog box if
 `use-dialog-box' is non-nil, and the window system or X toolkit in use
-provides a file dialog box.  */)
+provides a file dialog box.
+
+See also `read-file-name-completion-ignore-case'
+and `read-file-name-function'.  */)
      (prompt, dir, default_filename, mustmatch, initial, predicate)
      Lisp_Object prompt, dir, default_filename, mustmatch, initial, predicate;
 {
@@ -6051,10 +6227,13 @@ provides a file dialog box.  */)
 
   if (NILP (dir))
     dir = current_buffer->directory;
+  if (NILP (Ffile_name_absolute_p (dir)))
+    dir = Fexpand_file_name (dir, Qnil);
   if (NILP (default_filename))
-    default_filename = !NILP (initial)
-      ? Fexpand_file_name (initial, dir)
-      : current_buffer->filename;
+    default_filename
+      = (!NILP (initial)
+        ? Fexpand_file_name (initial, dir)
+        : current_buffer->filename);
 
   /* If dir starts with user's homedir, change that to ~. */
   homedir = (char *) egetenv ("HOME");
@@ -6134,20 +6313,16 @@ provides a file dialog box.  */)
     }
 
   count = SPECPDL_INDEX ();
-#ifdef VMS
-  specbind (intern ("completion-ignore-case"), Qt);
-#endif
-
+  specbind (intern ("completion-ignore-case"),
+           read_file_name_completion_ignore_case ? Qt : Qnil);
   specbind (intern ("minibuffer-completing-file-name"), Qt);
   specbind (intern ("read-file-name-predicate"),
            (NILP (predicate) ? Qfile_exists_p : predicate));
 
   GCPRO2 (insdef, default_filename);
 
-#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK)
-  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
-      && use_dialog_box
-      && have_menus_p ())
+#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) || defined (HAVE_CARBON)
+  if (! NILP (Fnext_read_file_uses_dialog_p ()))
     {
       /* If DIR contains a file name, split it.  */
       Lisp_Object file;
@@ -6159,7 +6334,8 @@ provides a file dialog box.  */)
        }
       if (!NILP(default_filename))
         default_filename = Fexpand_file_name (default_filename, dir);
-      val = Fx_file_dialog (prompt, dir, default_filename, mustmatch);
+      val = Fx_file_dialog (prompt, dir, default_filename, mustmatch,
+                            EQ (predicate, Qfile_directory_p) ? Qt : Qnil);
       add_to_history = 1;
     }
   else
@@ -6196,19 +6372,18 @@ provides a file dialog box.  */)
 
   if (!NILP (tem) && !NILP (default_filename))
     val = default_filename;
-  else if (SCHARS (val) == 0 && NILP (insdef))
-    {
-      if (!NILP (default_filename))
-       val = default_filename;
-      else
-       error ("No default file name");
-    }
   val = Fsubstitute_in_file_name (val);
 
   if (replace_in_history)
     /* Replace what Fcompleting_read added to the history
        with what we will actually return.  */
-    XSETCAR (Fsymbol_value (Qfile_name_history), double_dollars (val));
+    {
+       Lisp_Object val1 = double_dollars (val);
+       tem = Fsymbol_value (Qfile_name_history);
+       if (history_delete_duplicates)
+        XSETCDR (tem, Fdelete (val1, XCDR(tem)));
+       XSETCAR (tem, val1);
+    }
   else if (add_to_history)
     {
       /* Add the value to the history--but not if it matches
@@ -6216,8 +6391,10 @@ provides a file dialog box.  */)
       Lisp_Object val1 = double_dollars (val);
       tem = Fsymbol_value (Qfile_name_history);
       if (! CONSP (tem) || NILP (Fequal (XCAR (tem), val1)))
-       Fset (Qfile_name_history,
-             Fcons (val1, tem));
+       {
+         if (history_delete_duplicates) tem = Fdelete (val1, tem);
+         Fset (Qfile_name_history, Fcons (val1, tem));
+       }
     }
 
   return val;
@@ -6261,11 +6438,13 @@ syms_of_fileio ()
   Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
   Qfile_modes = intern ("file-modes");
   Qset_file_modes = intern ("set-file-modes");
+  Qset_file_times = intern ("set-file-times");
   Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
   Qinsert_file_contents = intern ("insert-file-contents");
   Qwrite_region = intern ("write-region");
   Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
   Qset_visited_file_modtime = intern ("set-visited-file-modtime");
+  Qauto_save_coding = intern ("auto-save-coding");
 
   staticpro (&Qexpand_file_name);
   staticpro (&Qsubstitute_in_file_name);
@@ -6293,11 +6472,13 @@ syms_of_fileio ()
   staticpro (&Qfile_accessible_directory_p);
   staticpro (&Qfile_modes);
   staticpro (&Qset_file_modes);
+  staticpro (&Qset_file_times);
   staticpro (&Qfile_newer_than_file_p);
   staticpro (&Qinsert_file_contents);
   staticpro (&Qwrite_region);
   staticpro (&Qverify_visited_file_modtime);
   staticpro (&Qset_visited_file_modtime);
+  staticpro (&Qauto_save_coding);
 
   Qfile_name_history = intern ("file-name-history");
   Fset (Qfile_name_history, Qnil);
@@ -6333,17 +6514,12 @@ instead use `file-name-coding-system' to get a constant encoding
 of file names regardless of the current language environment.  */);
   Vdefault_file_name_coding_system = Qnil;
 
-  DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format,
-    doc: /* *Format in which to write auto-save files.
-Should be a list of symbols naming formats that are defined in `format-alist'.
-If it is t, which is the default, auto-save files are written in the
-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);
+  Qafter_insert_file_set_coding = intern ("after-insert-file-set-coding");
+  staticpro (&Qafter_insert_file_set_coding);
 
   Qcar_less_than_car = intern ("car-less-than-car");
   staticpro (&Qcar_less_than_car);
@@ -6373,8 +6549,29 @@ same format as a regular save would use.  */);
               doc: /* Current predicate used by `read-file-name-internal'.  */);
   Vread_file_name_predicate = Qnil;
 
+  DEFVAR_BOOL ("read-file-name-completion-ignore-case", &read_file_name_completion_ignore_case,
+              doc: /* *Non-nil means when reading a file name completion ignores case.  */);
+#if defined VMS || defined DOS_NT || defined MAC_OS
+  read_file_name_completion_ignore_case = 1;
+#else
+  read_file_name_completion_ignore_case = 0;
+#endif
+
   DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
-              doc: /* *Non-nil means when reading a filename start with default dir in minibuffer.  */);
+              doc: /* *Non-nil means when reading a filename start with default dir in minibuffer.
+If the initial minibuffer contents are non-empty, you can usually
+request a default filename by typing RETURN without editing.  For some
+commands, exiting with an empty minibuffer has a special meaning,
+such as making the current buffer visit no file in the case of
+`set-visited-file-name'.
+If this variable is non-nil, the minibuffer contents are always
+initially non-empty and typing RETURN without editing will fetch the
+default name, if one is provided.  Note however that this default name
+is not necessarily the name originally inserted in the minibuffer, if
+that is just the default directory.
+If this variable is nil, the minibuffer often starts out empty.  In
+that case you may have to explicitly fetch the next history element to
+request the default name.  */);
   insert_default_directory = 1;
 
   DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
@@ -6433,8 +6630,13 @@ inserted at the specified positions of the file being written (1 means to
 insert before the first byte written).  The POSITIONs must be sorted into
 increasing order.  If there are several functions in the list, the several
 lists are merged destructively.  Alternatively, the function can return
-with a different buffer current and value nil.*/);
+with a different buffer current; in that case it should pay attention
+to the annotations returned by previous functions and listed in
+`write-region-annotations-so-far'.*/);
   Vwrite_region_annotate_functions = Qnil;
+  staticpro (&Qwrite_region_annotate_functions);
+  Qwrite_region_annotate_functions
+    = intern ("write-region-annotate-functions");
 
   DEFVAR_LISP ("write-region-annotations-so-far",
               &Vwrite_region_annotations_so_far,
@@ -6495,6 +6697,7 @@ a non-nil value.  */);
   defsubr (&Sfile_regular_p);
   defsubr (&Sfile_modes);
   defsubr (&Sset_file_modes);
+  defsubr (&Sset_file_times);
   defsubr (&Sset_default_file_modes);
   defsubr (&Sdefault_file_modes);
   defsubr (&Sfile_newer_than_file_p);
@@ -6512,8 +6715,12 @@ a non-nil value.  */);
 
   defsubr (&Sread_file_name_internal);
   defsubr (&Sread_file_name);
+  defsubr (&Snext_read_file_uses_dialog_p);
 
 #ifdef unix
   defsubr (&Sunix_sync);
 #endif
 }
+
+/* arch-tag: 64ba3fd7-f844-4fb2-ba4b-427eb928786c
+   (do not change this comment) */