(adjust_markers_for_delete): Make it non-static.
[bpt/emacs.git] / src / fileio.c
index 0e6eb79..b6c1e4d 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985,86,87,88,93,94,95,96,97,1998 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,93,94,95,96,97,98,1999 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -50,15 +50,6 @@ Boston, MA 02111-1307, USA.  */
 #include <pwd.h>
 #endif
 
-#ifdef MSDOS
-#include "msdos.h"
-#include <sys/param.h>
-#if __DJGPP__ >= 2
-#include <fcntl.h>
-#include <string.h>
-#endif
-#endif
-
 #include <ctype.h>
 
 #ifdef VMS
@@ -74,8 +65,6 @@ Boston, MA 02111-1307, USA.  */
 extern int errno;
 #endif
 
-extern char *strerror ();
-
 #ifdef APOLLO
 #include <sys/time.h>
 #endif
@@ -104,6 +93,15 @@ extern char *strerror ();
 #include <fcntl.h>
 #endif /* not WINDOWSNT */
 
+#ifdef MSDOS
+#include "msdos.h"
+#include <sys/param.h>
+#if __DJGPP__ >= 2
+#include <fcntl.h>
+#include <string.h>
+#endif
+#endif
+
 #ifdef DOS_NT
 #define CORRECT_DIR_SEPS(s) \
   do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
@@ -141,6 +139,9 @@ extern char *strerror ();
 #endif
 #endif
 
+#include "commands.h"
+extern int use_dialog_box;
+
 #ifndef O_WRONLY
 #define O_WRONLY 1
 #endif
@@ -149,6 +150,10 @@ extern char *strerror ();
 #define O_RDONLY 0
 #endif
 
+#ifndef S_ISLNK
+#  define lstat stat
+#endif
+
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #define max(a, b) ((a) > (b) ? (a) : (b))
 
@@ -206,6 +211,10 @@ Lisp_Object Vdirectory_sep_char;
 
 extern Lisp_Object Vuser_login_name;
 
+#ifdef WINDOWSNT
+extern Lisp_Object Vw32_get_true_file_attributes;
+#endif
+
 extern int minibuf_level;
 
 extern int minibuffer_auto_raise;
@@ -221,7 +230,7 @@ static Lisp_Object Vinhibit_file_name_handlers;
 static Lisp_Object Vinhibit_file_name_operation;
 
 Lisp_Object Qfile_error, Qfile_already_exists, Qfile_date_error;
-
+Lisp_Object Qexcl;
 Lisp_Object Qfile_name_history;
 
 Lisp_Object Qcar_less_than_car;
@@ -236,24 +245,34 @@ report_file_error (string, data)
      Lisp_Object data;
 {
   Lisp_Object errstring;
+  int errorno = errno;
 
-  errstring = build_string (strerror (errno));
-
-  /* System error messages are capitalized.  Downcase the initial
-     unless it is followed by a slash.  */
-  if (XSTRING (errstring)->data[1] != '/')
-    XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
+  synchronize_system_messages_locale ();
+  errstring = code_convert_string_norecord (build_string (strerror (errorno)),
+                                           Vlocale_coding_system, 0);
 
   while (1)
-    Fsignal (Qfile_error,
-            Fcons (build_string (string), Fcons (errstring, data)));
+    switch (errorno)
+      {
+      case EEXIST:
+       Fsignal (Qfile_already_exists, Fcons (errstring, data));
+       break;
+      default:
+       /* System error messages are capitalized.  Downcase the initial
+          unless it is followed by a slash.  */
+       if (XSTRING (errstring)->data[1] != '/')
+         XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
+
+       Fsignal (Qfile_error,
+                Fcons (build_string (string), Fcons (errstring, data)));
+      }
 }
 
 Lisp_Object
 close_file_unwind (fd)
      Lisp_Object fd;
 {
-  close (XFASTINT (fd));
+  emacs_close (XFASTINT (fd));
   return Qnil;
 }
 
@@ -322,19 +341,19 @@ use the standard functions without calling themselves recursively.")
     inhibited_handlers = Qnil;
 
   for (chain = Vfile_name_handler_alist; CONSP (chain);
-       chain = XCONS (chain)->cdr)
+       chain = XCDR (chain))
     {
       Lisp_Object elt;
-      elt = XCONS (chain)->car;
+      elt = XCAR (chain);
       if (CONSP (elt))
        {
          Lisp_Object string;
-         string = XCONS (elt)->car;
+         string = XCAR (elt);
          if (STRINGP (string) && fast_string_match (string, filename) >= 0)
            {
              Lisp_Object handler, tem;
 
-             handler = XCONS (elt)->cdr;
+             handler = XCDR (elt);
              tem = Fmemq (handler, inhibited_handlers);
              if (NILP (tem))
                return handler;
@@ -382,8 +401,11 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
         && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
 #endif /* VMS */
 #ifdef DOS_NT
-        /* only recognise drive specifier at beginning */
-        && !(p[-1] == ':' && p == beg + 2)
+        /* only recognise drive specifier at the beginning */
+        && !(p[-1] == ':'
+             /* handle the "/:d:foo" and "/:foo" cases correctly  */
+             && ((p == beg + 2 && !IS_DIRECTORY_SEP (*beg))
+                 || (p == beg + 4 && IS_DIRECTORY_SEP (*beg))))
 #endif
         ) p--;
 
@@ -391,11 +413,20 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
     return Qnil;
 #ifdef DOS_NT
   /* Expansion of "c:" to drive and default directory.  */
-  if (p == beg + 2 && beg[1] == ':')
+  if (p[-1] == ':')
     {
       /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir.  */
       unsigned char *res = alloca (MAXPATHLEN + 1);
-      if (getdefdir (toupper (*beg) - 'A' + 1, res))
+      unsigned char *r = res;
+
+      if (p == beg + 4 && IS_DIRECTORY_SEP (*beg) && beg[1] == ':')
+       {
+         strncpy (res, beg, 2);
+         beg += 2;
+         r += 2;
+       }
+
+      if (getdefdir (toupper (*beg) - 'A' + 1, r))
        {
          if (!IS_DIRECTORY_SEP (res[strlen (res) - 1]))
            strcat (res, "/");
@@ -440,7 +471,9 @@ or the entire name if it contains no slash.")
 #endif /* VMS */
 #ifdef DOS_NT
         /* only recognise drive specifier at beginning */
-        && !(p[-1] == ':' && p == beg + 2)
+        && !(p[-1] == ':'
+             /* handle the "/:d:foo" case correctly  */
+             && (p == beg + 2 || (p == beg + 4 && IS_DIRECTORY_SEP (*beg))))
 #endif
         )
     p--;
@@ -810,7 +843,11 @@ so there is no danger of generating a name being used by another process.\n\
 \n\
 In addition, this function makes an attempt to choose a name\n\
 which has no existing file.  To make this work,\n\
-PREFIX should be an absolute file name.")
+PREFIX should be an absolute file name.\n\
+\n\
+There is a race condition between calling `make-temp-name' and creating the\n\
+file which opens all kinds of security holes.  For that reason, you should\n\
+probably use `make-temp-file' instead.")
   (prefix)
      Lisp_Object prefix;
 {
@@ -852,7 +889,12 @@ PREFIX should be an absolute file name.")
   /* Here we try to minimize useless stat'ing when this function is
      invoked many times successively with the same PREFIX.  We achieve
      this by initializing count to a random value, and incrementing it
-     afterwards.  */
+     afterwards.
+
+     We don't want make-temp-name to be called while dumping,
+     because then make_temp_name_count_initialized_p would get set
+     and then make_temp_name_count would not be set when Emacs starts.  */
+
   if (!make_temp_name_count_initialized_p)
     {
       make_temp_name_count = (unsigned) time (NULL);
@@ -862,12 +904,17 @@ PREFIX should be an absolute file name.")
   while (1)
     {
       struct stat ignored;
-      unsigned num = make_temp_name_count++;
+      unsigned num = make_temp_name_count;
 
       p[0] = make_temp_name_tbl[num & 63], num >>= 6;
       p[1] = make_temp_name_tbl[num & 63], num >>= 6;
       p[2] = make_temp_name_tbl[num & 63], num >>= 6;
 
+      /* Poor man's congruential RN generator.  Replace with
+         ++make_temp_name_count for debugging.  */
+      make_temp_name_count += 25229;
+      make_temp_name_count %= 225307;
+
       if (stat (data, &ignored) < 0)
        {
          /* We want to return only if errno is ENOENT.  */
@@ -878,9 +925,9 @@ PREFIX should be an absolute file name.")
               can do.  The alternatives are to return nil, which is
               as bad as (and in many cases worse than) throwing the
               error, or to ignore the error, which will likely result
-              in looping through 262144 stat's, which is not only
-              SLOW, but also useless since it will fallback to the
-              errow below, anyway.  */
+              in looping through 225307 stat's, which is not only
+              dog-slow, but also useless since it will fallback to
+              the errow below, anyway.  */
            report_file_error ("Cannot create temporary name for prefix `%s'",
                               Fcons (prefix, Qnil));
          /* not reached */
@@ -925,6 +972,7 @@ See also the function `substitute-in-file-name'.")
 #ifdef DOS_NT
   int drive = 0;
   int collapse_newdir = 1;
+  int is_escaped = 0;
 #endif /* DOS_NT */
   int length;
   Lisp_Object handler;
@@ -968,7 +1016,7 @@ See also the function `substitute-in-file-name'.")
         is needed at all) without requiring it to be expanded now.  */
 #ifdef DOS_NT
       /* Detect MSDOS file names with drive specifiers.  */
-      && ! (IS_DRIVE (o[0]) && (IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])))
+      && ! (IS_DRIVE (o[0]) && IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2]))
 #ifdef WINDOWSNT
       /* Detect Windows file names in UNC format.  */
       && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1]))
@@ -1002,33 +1050,21 @@ See also the function `substitute-in-file-name'.")
      a local copy to modify, even if there ends up being no change. */
   nm = strcpy (alloca (strlen (nm) + 1), nm);
 
+  /* Note if special escape prefix is present, but remove for now.  */
+  if (nm[0] == '/' && nm[1] == ':')
+    {
+      is_escaped = 1;
+      nm += 2;
+    }
+
   /* Find and remove drive specifier if present; this makes nm absolute
-     even if the rest of the name appears to be relative. */
-  {
-    unsigned char *colon = rindex (nm, ':');
-
-    if (colon)
-      /* Only recognize colon as part of drive specifier if there is a
-        single alphabetic character preceeding the colon (and if the
-        character before the drive letter, if present, is a directory
-        separator); this is to support the remote system syntax used by
-        ange-ftp, and the "po:username" syntax for POP mailboxes. */
-    look_again:
-      if (nm == colon)
-       nm++;
-      else if (IS_DRIVE (colon[-1])
-              && (colon == nm + 1 || IS_DIRECTORY_SEP (colon[-2])))
-       {
-         drive = colon[-1];
-         nm = colon + 1;
-       }
-      else
-       {
-         while (--colon >= nm)
-           if (colon[0] == ':')
-             goto look_again;
-       }
-  }
+     even if the rest of the name appears to be relative.  Only look for
+     drive specifier at the beginning.  */
+  if (IS_DRIVE (nm[0]) && IS_DEVICE_SEP (nm[1]))
+    {
+      drive = nm[0];
+      nm += 2;
+    }
 
 #ifdef WINDOWSNT
   /* If we see "c://somedir", we want to strip the first slash after the
@@ -1053,10 +1089,10 @@ See also the function `substitute-in-file-name'.")
   if (
       IS_DIRECTORY_SEP (nm[0])
 #ifdef MSDOS
-      && drive
+      && drive && !is_escaped
 #endif
 #ifdef WINDOWSNT
-      && (drive || IS_DIRECTORY_SEP (nm[1]))
+      && (drive || IS_DIRECTORY_SEP (nm[1])) && !is_escaped
 #endif
 #ifdef VMS
       || index (nm, ':')
@@ -1302,6 +1338,14 @@ See also the function `substitute-in-file-name'.")
       && !newdir)
     {
       newdir = XSTRING (default_directory)->data;
+#ifdef DOS_NT
+      /* Note if special escape prefix is present, but remove for now.  */
+      if (newdir[0] == '/' && newdir[1] == ':')
+       {
+         is_escaped = 1;
+         newdir += 2;
+       }
+#endif
     }
 
 #ifdef DOS_NT
@@ -1377,9 +1421,9 @@ See also the function `substitute-in-file-name'.")
   if (newdir)
     {
       /* Get rid of any slash at the end of newdir, unless newdir is
-        just // (an incomplete UNC name).  */
+        just / or // (an incomplete UNC name).  */
       length = strlen (newdir);
-      if (length > 0 && IS_DIRECTORY_SEP (newdir[length - 1])
+      if (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1])
 #ifdef WINDOWSNT
          && !(length == 2 && IS_DIRECTORY_SEP (newdir[0]))
 #endif
@@ -1398,10 +1442,11 @@ See also the function `substitute-in-file-name'.")
   /* Now concatenate the directory and name to new space in the stack frame */
   tlen += strlen (nm) + 1;
 #ifdef DOS_NT
-  /* Add reserved space for drive name.  (The Microsoft x86 compiler
+  /* Reserve space for drive specifier and escape prefix, since either
+     or both may need to be inserted.  (The Microsoft x86 compiler
      produces incorrect code if the following two lines are combined.)  */
-  target = (unsigned char *) alloca (tlen + 2);
-  target += 2;
+  target = (unsigned char *) alloca (tlen + 4);
+  target += 4;
 #else  /* not DOS_NT */
   target = (unsigned char *) alloca (tlen);
 #endif /* not DOS_NT */
@@ -1411,7 +1456,18 @@ See also the function `substitute-in-file-name'.")
     {
 #ifndef VMS
       if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0]))
-       strcpy (target, newdir);
+       {
+#ifdef DOS_NT
+         /* If newdir is effectively "C:/", then the drive letter will have
+            been stripped and newdir will be "/".  Concatenating with an
+            absolute directory in nm produces "//", which will then be
+            incorrectly treated as a network share.  Ignore newdir in
+            this case (keeping the drive letter).  */
+         if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0]) 
+               && newdir[1] == '\0'))
+#endif
+           strcpy (target, newdir);
+       }
       else
 #endif
        file_name_as_directory (target, newdir);
@@ -1520,6 +1576,13 @@ See also the function `substitute-in-file-name'.")
       target[0] = DRIVE_LETTER (drive);
       target[1] = ':';
     }
+  /* Reinsert the escape prefix if required.  */
+  if (is_escaped)
+    {
+      target -= 2;
+      target[0] = '/';
+      target[1] = ':';
+    }
   CORRECT_DIR_SEPS (target);
 #endif /* DOS_NT */
 
@@ -2067,7 +2130,7 @@ duplicates what `expand-file-name' does.")
       xnm = p;
 #ifdef DOS_NT
     else if (IS_DRIVE (p[0]) && p[1] == ':'
-            && p > nm && IS_DIRECTORY_SEP (p[-1]))
+            && p > xnm && IS_DIRECTORY_SEP (p[-1]))
       xnm = p;
 #endif
 
@@ -2134,13 +2197,15 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
      struct stat *statptr;
      int quick;
 {
-  register Lisp_Object tem;
+  register Lisp_Object tem, encoded_filename;
   struct stat statbuf;
   struct gcpro gcpro1;
 
+  encoded_filename = ENCODE_FILE (absname);
+
   /* stat is a good way to tell whether the file exists,
      regardless of what access permissions it has.  */
-  if (stat (XSTRING (absname)->data, &statbuf) >= 0)
+  if (stat (XSTRING (encoded_filename)->data, &statbuf) >= 0)
     {
       if (! interactive)
        Fsignal (Qfile_already_exists,
@@ -2219,7 +2284,7 @@ A prefix arg makes KEEP-TIME non-nil.")
   else if (stat (XSTRING (encoded_newname)->data, &out_st) < 0)
     out_st.st_mode = 0;
 
-  ifd = open (XSTRING (encoded_file)->data, O_RDONLY);
+  ifd = emacs_open (XSTRING (encoded_file)->data, O_RDONLY, 0);
   if (ifd < 0)
     report_file_error ("Opening input file", Fcons (file, Qnil));
 
@@ -2229,7 +2294,7 @@ A prefix arg makes KEEP-TIME non-nil.")
      copyable by us. */
   input_file_statable_p = (fstat (ifd, &st) >= 0);
 
-#if !defined (MSDOS) || __DJGPP__ > 1
+#if !defined (DOS_NT) || __DJGPP__ > 1
   if (out_st.st_mode != 0
       && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
     {
@@ -2271,13 +2336,13 @@ A prefix arg makes KEEP-TIME non-nil.")
 
   immediate_quit = 1;
   QUIT;
-  while ((n = read (ifd, buf, sizeof buf)) > 0)
-    if (write (ofd, buf, n) != n)
+  while ((n = emacs_read (ifd, buf, sizeof buf)) > 0)
+    if (emacs_write (ofd, buf, n) != n)
       report_file_error ("I/O error", Fcons (newname, Qnil));
   immediate_quit = 0;
 
   /* Closing the output clobbers the file times on some systems.  */
-  if (close (ofd) < 0)
+  if (emacs_close (ofd) < 0)
     report_file_error ("I/O error", Fcons (newname, Qnil));
 
   if (input_file_statable_p)
@@ -2307,7 +2372,7 @@ A prefix arg makes KEEP-TIME non-nil.")
 #endif /* MSDOS */
     }
 
-  close (ifd);
+  emacs_close (ifd);
 
   /* Discard the unwind protects.  */
   specpdl_ptr = specpdl + count;
@@ -2846,10 +2911,10 @@ See also `file-exists-p' and `file-attributes'.")
   if (S_ISFIFO (statbuf.st_mode))
     flags |= O_NONBLOCK;
 #endif
-  desc = open (XSTRING (absname)->data, flags);
+  desc = emacs_open (XSTRING (absname)->data, flags, 0);
   if (desc < 0)
     return Qnil;
-  close (desc);
+  emacs_close (desc);
   return Qt;
 #endif /* not DOS_NT */
 }
@@ -2905,6 +2970,7 @@ If there is no error, we return nil.")
   int fd;
 
   CHECK_STRING (filename, 0);
+  CHECK_STRING (string, 1);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -2914,10 +2980,10 @@ If there is no error, we return nil.")
 
   encoded_filename = ENCODE_FILE (filename);
 
-  fd = open (XSTRING (encoded_filename)->data, O_RDONLY);
+  fd = emacs_open (XSTRING (encoded_filename)->data, O_RDONLY, 0);
   if (fd < 0)
     report_file_error (XSTRING (string)->data, Fcons (filename, Qnil));
-  close (fd);
+  emacs_close (fd);
 
   return Qnil;
 }
@@ -2973,7 +3039,9 @@ Otherwise returns nil.")
 }
 
 DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
-  "Return t if FILENAME names an existing directory.")
+  "Return t if FILENAME names an existing directory.\n\
+Symbolic links to directories count as directories.\n\
+See `file-symlink-p' to distinguish symlinks.")
   (filename)
      Lisp_Object filename;
 {
@@ -3049,9 +3117,25 @@ This is the sort of file that holds an ordinary stream of data bytes.")
 
   absname = ENCODE_FILE (absname);
 
+#ifdef WINDOWSNT
+  {
+    int result;
+    Lisp_Object tem = Vw32_get_true_file_attributes;
+
+    /* Tell stat to use expensive method to get accurate info.  */
+    Vw32_get_true_file_attributes = Qt;
+    result = stat (XSTRING (absname)->data, &st);
+    Vw32_get_true_file_attributes = tem;
+
+    if (result < 0)
+      return Qnil;
+    return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil;
+  }
+#else
   if (stat (XSTRING (absname)->data, &st) < 0)
     return Qnil;
   return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil;
+#endif
 }
 \f
 DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
@@ -3204,6 +3288,48 @@ Lisp_Object Qfind_buffer_file_type;
 #define READ_BUF_SIZE (64 << 10)
 #endif
 
+extern void adjust_markers_for_delete P_ ((int, int, int, int));
+
+/* This function is called after Lisp functions to decide a coding
+   system are called, or when they cause an error.  Before they are
+   called, the current buffer is set unibyte and it contains only a
+   newly inserted text (thus the buffer was empty before the
+   insertion).
+
+   The functions may set markers, overlays, text properties, or even
+   alter the buffer contents, change the current buffer.
+
+   Here, we reset all those changes by:
+       o set back the current buffer.
+       o move all markers and overlays to BEG.
+       o remove all text properties.
+       o set back the buffer multibyteness.  */
+
+static Lisp_Object
+decide_coding_unwind (unwind_data)
+     Lisp_Object unwind_data;
+{
+  Lisp_Object multibyte, undo_list, buffer;
+
+  multibyte = XCAR (unwind_data);
+  unwind_data = XCDR (unwind_data);
+  undo_list = XCAR (unwind_data);
+  buffer = XCDR (unwind_data);
+
+  if (current_buffer != XBUFFER (buffer))
+    set_buffer_internal (XBUFFER (buffer));
+  adjust_markers_for_delete (BEG, BEG_BYTE, Z, Z_BYTE);
+  adjust_overlays_for_delete (BEG, Z - BEG);
+  BUF_INTERVALS (current_buffer) = 0;
+  TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+
+  /* Now we are safe to change the buffer's multibyteness directly.  */
+  current_buffer->enable_multibyte_characters = multibyte;
+  current_buffer->undo_list = undo_list;
+
+  return Qnil;
+}
+
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
   1, 5, 0,
   "Insert contents of file FILENAME after point.\n\
@@ -3224,10 +3350,11 @@ the whole thing because (1) it preserves some marker positions\n\
 and (2) it puts less data in the undo list.\n\
 When REPLACE is non-nil, the value is the number of characters actually read,\n\
 which is often less than the number of characters to be read.\n\
+\n\
 This does code conversion according to the value of\n\
-  `coding-system-for-read' or `file-coding-system-alist',\n\
-  and sets the variable `last-coding-system-used' to the coding system\n\
-  actually used.")
+`coding-system-for-read' or `file-coding-system-alist',\n\
+and sets the variable `last-coding-system-used' to the coding system\n\
+actually used.")
   (filename, visit, beg, end, replace)
      Lisp_Object filename, visit, beg, end, replace;
 {
@@ -3242,11 +3369,12 @@ This does code conversion according to the value of\n\
   Lisp_Object p;
   int total;
   int not_regular = 0;
-  char read_buf[READ_BUF_SIZE];
+  unsigned char read_buf[READ_BUF_SIZE];
   struct coding_system coding;
   unsigned char buffer[1 << 14];
   int replace_handled = 0;
   int set_coding_system = 0;
+  int coding_system_decided = 0;
 
   if (current_buffer->base_buffer && ! NILP (visit))
     error ("Cannot do file visiting in an indirect buffer");
@@ -3270,6 +3398,8 @@ This does code conversion according to the value of\n\
     {
       val = call6 (handler, Qinsert_file_contents, filename,
                   visit, beg, end, replace);
+      if (CONSP (val) && CONSP (XCDR (val)))
+       inserted = XINT (XCAR (XCDR (val)));
       goto handled;
     }
 
@@ -3278,21 +3408,33 @@ This does code conversion according to the value of\n\
 
   fd = -1;
 
+#ifdef WINDOWSNT
+  {
+    Lisp_Object tem = Vw32_get_true_file_attributes;
+
+    /* Tell stat to use expensive method to get accurate info.  */
+    Vw32_get_true_file_attributes = Qt;
+    total = stat (XSTRING (filename)->data, &st);
+    Vw32_get_true_file_attributes = tem;
+  }
+  if (total < 0)
+#else
 #ifndef APOLLO
   if (stat (XSTRING (filename)->data, &st) < 0)
 #else
-  if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0
+  if ((fd = emacs_open (XSTRING (filename)->data, O_RDONLY, 0)) < 0
       || fstat (fd, &st) < 0)
 #endif /* not APOLLO */
+#endif /* WINDOWSNT */
     {
-      if (fd >= 0) close (fd);
+      if (fd >= 0) emacs_close (fd);
     badopen:
       if (NILP (visit))
        report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
       st.st_mtime = -1;
       how_much = 0;
       if (!NILP (Vcoding_system_for_read))
-       current_buffer->buffer_file_coding_system = Vcoding_system_for_read;
+       Fset (Qbuffer_file_coding_system, Vcoding_system_for_read);
       goto notfound;
     }
 
@@ -3315,7 +3457,7 @@ This does code conversion according to the value of\n\
 #endif
 
   if (fd < 0)
-    if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0)
+    if ((fd = emacs_open (XSTRING (filename)->data, O_RDONLY, 0)) < 0)
       goto badopen;
 
   /* Replacement should preserve point as it preserves markers.  */
@@ -3328,6 +3470,9 @@ This does code conversion according to the value of\n\
   if (! not_regular && st.st_size < 0)
     error ("File size is negative");
 
+  /* Prevent redisplay optimizations.  */
+  current_buffer->clip_changed = 1;
+
   if (!NILP (beg) || !NILP (end))
     if (!NILP (visit))
       error ("Attempt to visit less than an entire file");
@@ -3344,82 +3489,113 @@ This does code conversion according to the value of\n\
       if (! not_regular)
        {
          XSETINT (end, st.st_size);
-         if (XINT (end) != st.st_size)
+
+         /* Arithmetic overflow can occur if an Emacs integer cannot
+            represent the file size, or if the calculations below
+            overflow.  The calculations below double the file size
+            twice, so check that it can be multiplied by 4 safely.  */
+         if (XINT (end) != st.st_size
+             || ((int) st.st_size * 4) / 4 != st.st_size)
            error ("Maximum buffer size exceeded");
        }
     }
 
-  /* Decide the coding-system of the file.  */
-  {
-    Lisp_Object val = Qnil;
+  if (BEG < Z)
+    {
+      /* Decide the coding system to use for reading the file now
+         because we can't use an optimized method for handling
+         `coding:' tag if the current buffer is not empty.  */
+      Lisp_Object val;
+      val = Qnil;
 
-    if (!NILP (Vcoding_system_for_read))
-      val = Vcoding_system_for_read;
-    else
-      {
-       if (! NILP (Vset_auto_coding_function))
-         {
-           /* Find a coding system specified in the heading two lines
-              or in the tailing several lines of the file.  We assume
-              that the 1K-byte and 3K-byte for heading and tailing
-              respectively are sufficient fot this purpose.  */
-           int how_many, nread;
-
-           if (st.st_size <= (1024 * 4))
-             nread = read (fd, read_buf, 1024 * 4);
-           else
-             {
-               nread = read (fd, read_buf, 1024);
-               if (nread >= 0)
-                 {
-                   if (lseek (fd, st.st_size - (1024 * 3), 0) < 0)
-                     report_file_error ("Setting file position",
-                                        Fcons (orig_filename, Qnil));
-                   nread += read (fd, read_buf + nread, 1024 * 3);
-                 }
-             }
-        
-           if (nread < 0)
-             error ("IO error reading %s: %s",
-                    XSTRING (orig_filename)->data, strerror (errno));
-           else if (nread > 0)
-             {
-               Lisp_Object tem;
-               /* Always make this a unibyte string
-                  because we have not yet decoded it.  */
-               tem = make_unibyte_string (read_buf, nread);
-               val = call1 (Vset_auto_coding_function, tem);
-               /* Rewind the file for the actual read done later.  */
-               if (lseek (fd, 0, 0) < 0)
-                 report_file_error ("Setting file position",
-                                    Fcons (orig_filename, Qnil));
-             }
-         }
-       if (NILP (val))
-         {
-           Lisp_Object args[6], coding_systems;
+      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
+            specification if it is not seekable.  */
+         if (! not_regular && ! NILP (Vset_auto_coding_function))
+           {
+             /* Find a coding system specified in the heading two
+                lines or in the tailing several lines of the file.
+                We assume that the 1K-byte and 3K-byte for heading
+                and tailing respectively are sufficient for this
+                purpose.  */
+             int how_many, nread;
+
+             if (st.st_size <= (1024 * 4))
+               nread = emacs_read (fd, read_buf, 1024 * 4);
+             else
+               {
+                 nread = emacs_read (fd, read_buf, 1024);
+                 if (nread >= 0)
+                   {
+                     if (lseek (fd, st.st_size - (1024 * 3), 0) < 0)
+                       report_file_error ("Setting file position",
+                                          Fcons (orig_filename, Qnil));
+                     nread += emacs_read (fd, read_buf + nread, 1024 * 3);
+                   }
+               }
 
-           args[0] = Qinsert_file_contents, args[1] = orig_filename,
-             args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
-           coding_systems = Ffind_operation_coding_system (6, args);
-           if (CONSP (coding_systems)) val = XCONS (coding_systems)->car;
-         }
-      }
+             if (nread < 0)
+               error ("IO error reading %s: %s",
+                      XSTRING (orig_filename)->data, emacs_strerror (errno));
+             else if (nread > 0)
+               {
+                 int count = specpdl_ptr - specpdl;
+                 struct buffer *prev = current_buffer;
+
+                 record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+                 temp_output_buffer_setup (" *code-converting-work*");
+                 set_buffer_internal (XBUFFER (Vstandard_output));
+                 current_buffer->enable_multibyte_characters = Qnil;
+                 insert_1_both (read_buf, nread, nread, 0, 0, 0);
+                 TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
+                 val = call2 (Vset_auto_coding_function,
+                              filename, make_number (nread));
+                 set_buffer_internal (prev);
+                 /* Discard the unwind protect for recovering the
+                     current buffer.  */
+                 specpdl_ptr--;
+
+                 /* Rewind the file for the actual read done later.  */
+                 if (lseek (fd, 0, 0) < 0)
+                   report_file_error ("Setting file position",
+                                      Fcons (orig_filename, Qnil));
+               }
+           }
 
-    if (NILP (Vcoding_system_for_read)
-       && NILP (current_buffer->enable_multibyte_characters))
-      {
-       /* We must suppress all text conversion except for end-of-line
-          conversion.  */
-       struct coding_system coding_temp;
+         if (NILP (val))
+           {
+             /* If we have not yet decided a coding system, check
+                 file-coding-system-alist.  */
+             Lisp_Object args[6], coding_systems;
+
+             args[0] = Qinsert_file_contents, args[1] = orig_filename;
+             args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace;
+             coding_systems = Ffind_operation_coding_system (6, args);
+             if (CONSP (coding_systems))
+               val = XCAR (coding_systems);
+           }
+       }
 
-       setup_coding_system (Fcheck_coding_system (val), &coding_temp);
-       setup_coding_system (Qraw_text, &coding);
-       coding.eol_type = coding_temp.eol_type;
-      }
-    else
       setup_coding_system (Fcheck_coding_system (val), &coding);
-  }
+
+      if (NILP (current_buffer->enable_multibyte_characters)
+         && ! NILP (val))
+       /* We must suppress all character code conversion except for
+          end-of-line conversion.  */
+       setup_raw_text_coding_system (&coding);
+
+      coding_system_decided = 1;
+    }
+
+  /* Ensure we always set Vlast_coding_system_used.  */
+  set_coding_system = 1;
 
   /* If requested, replace the accessible part of the buffer
      with the file contents.  Avoid replacing text at the
@@ -3436,7 +3612,10 @@ This does code conversion according to the value of\n\
      But if we discover the need for conversion, we give up on this method
      and let the following if-statement handle the replace job.  */
   if (!NILP (replace)
-      && ! CODING_REQUIRE_DECODING (&coding))
+      && BEGV < ZV
+      && ! CODING_REQUIRE_DECODING (&coding)
+      && (coding.eol_type == CODING_EOL_UNDECIDED
+         || coding.eol_type == CODING_EOL_LF))
     {
       /* same_at_start and same_at_end count bytes,
         because file access counts bytes
@@ -3464,10 +3643,10 @@ This does code conversion according to the value of\n\
        {
          int nread, bufpos;
 
-         nread = read (fd, buffer, sizeof buffer);
+         nread = emacs_read (fd, buffer, sizeof buffer);
          if (nread < 0)
            error ("IO error reading %s: %s",
-                  XSTRING (orig_filename)->data, strerror (errno));
+                  XSTRING (orig_filename)->data, emacs_strerror (errno));
          else if (nread == 0)
            break;
 
@@ -3506,7 +3685,7 @@ This does code conversion according to the value of\n\
         there's no need to replace anything.  */
       if (same_at_start - BEGV_BYTE == XINT (end))
        {
-         close (fd);
+         emacs_close (fd);
          specpdl_ptr--;
          /* Truncate the buffer to the size of the file.  */
          del_range_1 (same_at_start, same_at_end, 0);
@@ -3535,10 +3714,10 @@ This does code conversion according to the value of\n\
          total_read = 0;
          while (total_read < trial)
            {
-             nread = read (fd, buffer + total_read, trial - total_read);
+             nread = emacs_read (fd, buffer + total_read, trial - total_read);
              if (nread <= 0)
                error ("IO error reading %s: %s",
-                      XSTRING (orig_filename)->data, strerror (errno));
+                      XSTRING (orig_filename)->data, emacs_strerror (errno));
              total_read += nread;
            }
          /* Scan this bufferful from the end, comparing with
@@ -3572,7 +3751,14 @@ This does code conversion according to the value of\n\
 
          /* We win!  We can handle REPLACE the optimized way.  */
 
-         /* Extends the end of non-matching text area to multibyte
+         /* Extend the start of non-matching text area to multibyte
+             character boundary.  */
+         if (! NILP (current_buffer->enable_multibyte_characters))
+           while (same_at_start > BEGV_BYTE
+                  && ! CHAR_HEAD_P (FETCH_BYTE (same_at_start)))
+             same_at_start--;
+
+         /* Extend the end of non-matching text area to multibyte
              character boundary.  */
          if (! NILP (current_buffer->enable_multibyte_characters))
            while (same_at_end < ZV_BYTE
@@ -3612,7 +3798,7 @@ This does code conversion according to the value of\n\
      is needed, in a simple way that needs a lot of memory.
      The preceding if-statement handles the case of no conversion
      in a more optimized way.  */
-  if (!NILP (replace) && ! replace_handled)
+  if (!NILP (replace) && ! replace_handled && BEGV < ZV)
     {
       int same_at_start = BEGV_BYTE;
       int same_at_end = ZV_BYTE;
@@ -3628,7 +3814,7 @@ This does code conversion according to the value of\n\
 
       if (lseek (fd, XINT (beg), 0) < 0)
        {
-         free (conversion_buffer);
+         xfree (conversion_buffer);
          report_file_error ("Setting file position",
                             Fcons (orig_filename, Qnil));
        }
@@ -3642,13 +3828,13 @@ This does code conversion according to the value of\n\
        {
          /* try is reserved in some compilers (Microsoft C) */
          int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
-         char *destination = read_buf + unprocessed;
+         unsigned char *destination = read_buf + unprocessed;
          int this;
 
          /* Allow quitting out of the actual I/O.  */
          immediate_quit = 1;
          QUIT;
-         this = read (fd, destination, trytry);
+         this = emacs_read (fd, destination, trytry);
          immediate_quit = 0;
 
          if (this < 0 || this + unprocessed == 0)
@@ -3697,11 +3883,11 @@ This does code conversion according to the value of\n\
 
       if (how_much < 0)
        {
-         free (conversion_buffer);
+         xfree (conversion_buffer);
 
          if (how_much == -1)
            error ("IO error reading %s: %s",
-                  XSTRING (orig_filename)->data, strerror (errno));
+                  XSTRING (orig_filename)->data, emacs_strerror (errno));
          else if (how_much == -2)
            error ("maximum buffer size exceeded");
        }
@@ -3719,14 +3905,22 @@ This does code conversion according to the value of\n\
 
       if (bufpos == inserted)
        {
-         free (conversion_buffer);
-         close (fd);
+         xfree (conversion_buffer);
+         emacs_close (fd);
          specpdl_ptr--;
          /* Truncate the buffer to the size of the file.  */
-         del_range_1 (same_at_start, same_at_end, 0);
+         del_range_byte (same_at_start, same_at_end, 0);
+         inserted = 0;
          goto handled;
        }
 
+      /* Extend the start of non-matching text area to multibyte
+        character boundary.  */
+      if (! NILP (current_buffer->enable_multibyte_characters))
+       while (same_at_start > BEGV_BYTE
+              && ! CHAR_HEAD_P (FETCH_BYTE (same_at_start)))
+         same_at_start--;
+
       /* Scan this bufferful from the end, comparing with
         the Emacs buffer.  */
       bufpos = inserted;
@@ -3737,6 +3931,13 @@ This does code conversion according to the value of\n\
             && FETCH_BYTE (same_at_end - 1) == conversion_buffer[bufpos - 1])
        same_at_end--, bufpos--;
 
+      /* Extend the end of non-matching text area to multibyte
+        character boundary.  */
+      if (! NILP (current_buffer->enable_multibyte_characters))
+       while (same_at_end < ZV_BYTE
+              && ! CHAR_HEAD_P (FETCH_BYTE (same_at_end)))
+         same_at_end++;
+
       /* Don't try to reuse the same piece of text twice.  */
       overlap = same_at_start - BEGV_BYTE - (same_at_end + inserted - ZV_BYTE);
       if (overlap > 0)
@@ -3751,14 +3952,26 @@ This does code conversion according to the value of\n\
         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);
-      del_range_byte (same_at_start, same_at_end, 0);
-      SET_PT_BOTH (GPT, GPT_BYTE);
 
+      if (same_at_end != same_at_start)
+       {
+         del_range_byte (same_at_start, same_at_end, 0);
+         temp = GPT;
+         same_at_start = GPT_BYTE;
+       }
+      else
+       {
+         temp = BYTE_TO_CHAR (same_at_start);
+       }
+      /* 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,
                0, 0, 0);
+      /* Set `inserted' to the number of inserted characters.  */
+      inserted = PT - temp;
 
       free (conversion_buffer);
-      close (fd);
+      emacs_close (fd);
       specpdl_ptr--;
 
       goto handled;
@@ -3815,7 +4028,8 @@ This does code conversion according to the value of\n\
       /* Allow quitting out of the actual I/O.  */
       immediate_quit = 1;
       QUIT;
-      this = read (fd, BYTE_POS_ADDR (PT_BYTE + inserted - 1) + 1, trytry);
+      this = emacs_read (fd, BYTE_POS_ADDR (PT_BYTE + inserted - 1) + 1,
+                        trytry);
       immediate_quit = 0;
 
       if (this <= 0)
@@ -3846,16 +4060,86 @@ This does code conversion according to the value of\n\
     /* Put an anchor to ensure multi-byte form ends at gap.  */
     *GPT_ADDR = 0;
 
-  close (fd);
+  emacs_close (fd);
 
   /* Discard the unwind protect for closing the file.  */
   specpdl_ptr--;
 
   if (how_much < 0)
     error ("IO error reading %s: %s",
-          XSTRING (orig_filename)->data, strerror (errno));
+          XSTRING (orig_filename)->data, emacs_strerror (errno));
 
-  if (inserted > 0)
+  if (! coding_system_decided)
+    {
+      /* The coding system is not yet decided.  Decide it by an
+        optimized method for handling `coding:' tag.
+
+        Note that we can get here only if the buffer was empty
+        before the insertion.  */
+      Lisp_Object val;
+      val = Qnil;
+
+      if (!NILP (Vcoding_system_for_read))
+       val = Vcoding_system_for_read;
+      else
+       {
+         /* Since we are sure that the current buffer was empty
+            before the insertion, we can toggle
+            enable-multibyte-characters directly here without taking
+            care of marker adjustment and byte combining problem.  By
+            this way, we can run Lisp program safely before decoding
+            the inserted text.  */
+         Lisp_Object unwind_data;
+             int count = specpdl_ptr - specpdl;
+
+         unwind_data = Fcons (current_buffer->enable_multibyte_characters,
+                              Fcons (current_buffer->undo_list,
+                                     Fcurrent_buffer ()));
+             current_buffer->enable_multibyte_characters = Qnil;
+         current_buffer->undo_list = Qt;
+         record_unwind_protect (decide_coding_unwind, unwind_data);
+
+         if (inserted > 0 && ! NILP (Vset_auto_coding_function))
+           {
+             val = call2 (Vset_auto_coding_function,
+                          filename, make_number (inserted));
+           }
+
+         if (NILP (val))
+           {
+             /* If the coding system is not yet decided, check
+                file-coding-system-alist.  */
+             Lisp_Object args[6], coding_systems;
+
+             args[0] = Qinsert_file_contents, args[1] = orig_filename;
+             args[2] = visit, args[3] = beg, args[4] = end, args[5] = Qnil;
+             coding_systems = Ffind_operation_coding_system (6, args);
+             if (CONSP (coding_systems))
+               val = XCAR (coding_systems);
+           }
+
+         unbind_to (count, Qnil);
+         inserted = Z_BYTE - BEG_BYTE;
+       }
+
+      /* The following kludgy code is to avoid some compiler bug.
+        We can't simply do
+        setup_coding_system (val, &coding);
+        on some system.  */
+      {
+       struct coding_system temp_coding;
+       setup_coding_system (val, &temp_coding);
+       bcopy (&temp_coding, &coding, sizeof coding);
+      }
+
+      if (NILP (current_buffer->enable_multibyte_characters)
+         && ! NILP (val))
+       /* We must suppress all character code conversion except for
+          end-of-line conversion.  */
+       setup_raw_text_coding_system (&coding);
+    }
+
+  if (inserted > 0 || coding.type == coding_type_ccl)
     {
       if (CODING_MAY_REQUIRE_DECODING (&coding))
        {
@@ -3883,20 +4167,19 @@ This does code conversion according to the value of\n\
       else
        adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
                             inserted);
+    }
 
 #ifdef DOS_NT
-      /* Use the conversion type to determine buffer-file-type
-        (find-buffer-file-type is now used to help determine the
-        conversion).  */
-      if (coding.eol_type != CODING_EOL_UNDECIDED 
-         && coding.eol_type != CODING_EOL_LF)
-       current_buffer->buffer_file_type = Qnil;
-      else
-       current_buffer->buffer_file_type = Qt;
+  /* Use the conversion type to determine buffer-file-type
+     (find-buffer-file-type is now used to help determine the
+     conversion).  */
+  if ((coding.eol_type == CODING_EOL_UNDECIDED 
+       || coding.eol_type == CODING_EOL_LF)
+      && ! CODING_REQUIRE_DECODING (&coding))
+    current_buffer->buffer_file_type = Qt;
+  else
+    current_buffer->buffer_file_type = Qnil;
 #endif
-    }
-
-  set_coding_system = 1;
 
  notfound:
  handled:
@@ -4021,12 +4304,22 @@ 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\
-The optional seventh arg CONFIRM, if non-nil, says ask for confirmation\n\
-  before overwriting an existing file.\n\
+The optional seventh arg MUSTBENEW, if non-nil, insists on a check\n\
+  for an existing file with the same name.  If MUSTBENEW is `excl',\n\
+  that means to get an error if the file already exists; never overwrite.\n\
+  If MUSTBENEW is neither nil nor `excl', that means ask for\n\
+  confirmation before overwriting, but do go ahead and overwrite the file\n\
+  if the user confirms.\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, lockname, confirm)
-     Lisp_Object start, end, filename, append, visit, lockname, confirm;
+to the file, instead of any buffer contents, and END is ignored.\n\
+\n\
+This does code conversion according to the value of\n\
+`coding-system-for-write', `buffer-file-coding-system', or\n\
+`file-coding-system-alist', and sets the variable\n\
+`last-coding-system-used' to the coding system actually used.")
+
+  (start, end, filename, append, visit, lockname, mustbenew)
+     Lisp_Object start, end, filename, append, visit, lockname, mustbenew;
 {
   register int desc;
   int failure;
@@ -4067,7 +4360,7 @@ to the file, instead of any buffer contents, and END is ignored.")
       val = Qnil;
     else if (!NILP (Vcoding_system_for_write))
       val = Vcoding_system_for_write;
-    else if (NILP (current_buffer->enable_multibyte_characters))
+    else
       {
        /* If the variable `buffer-file-coding-system' is set locally,
           it means that the file was read with some kind of code
@@ -4078,38 +4371,72 @@ to the file, instead of any buffer contents, and END is ignored.")
           If it is not set locally, we anyway have to convert EOL
           format if the default value of `buffer-file-coding-system'
           tells that it is not Unix-like (LF only) format.  */
+       int using_default_coding = 0;
+       int force_raw_text = 0;
+
        val = current_buffer->buffer_file_coding_system;
-       if (NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil)))
+       if (NILP (val)
+           || NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil)))
+         {
+           val = Qnil;
+           if (NILP (current_buffer->enable_multibyte_characters))
+             force_raw_text = 1;
+         }
+       
+       if (NILP (val))
+         {
+           /* Check file-coding-system-alist.  */
+           Lisp_Object args[7], coding_systems;
+
+           args[0] = Qwrite_region; args[1] = start; args[2] = end;
+           args[3] = filename; args[4] = append; args[5] = visit;
+           args[6] = lockname;
+           coding_systems = Ffind_operation_coding_system (7, args);
+           if (CONSP (coding_systems) && !NILP (XCDR (coding_systems)))
+             val = XCDR (coding_systems);
+         }
+
+       if (NILP (val)
+           && !NILP (current_buffer->buffer_file_coding_system))
          {
-           struct coding_system coding_temp;
+           /* If we still have not decided a coding system, use the
+              default value of buffer-file-coding-system.  */
+           val = current_buffer->buffer_file_coding_system;
+           using_default_coding = 1;
+         }
+           
+       if (!force_raw_text
+           && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
+         /* Confirm that VAL can surely encode the current region.  */
+         val = call3 (Vselect_safe_coding_system_function, start, end, val);
 
-           setup_coding_system (Fcheck_coding_system (val), &coding_temp);
-           if (coding_temp.eol_type == CODING_EOL_CRLF
-               || coding_temp.eol_type == CODING_EOL_CR)
+       setup_coding_system (Fcheck_coding_system (val), &coding);
+       if (coding.eol_type == CODING_EOL_UNDECIDED
+           && !using_default_coding)
+         {
+           if (! EQ (default_buffer_file_coding.symbol,
+                     buffer_defaults.buffer_file_coding_system))
+             setup_coding_system (buffer_defaults.buffer_file_coding_system,
+                                  &default_buffer_file_coding);
+           if (default_buffer_file_coding.eol_type != CODING_EOL_UNDECIDED)
              {
-               setup_coding_system (Qraw_text, &coding);
-               coding.eol_type = coding_temp.eol_type;
-               goto done_setup_coding;
+               Lisp_Object subsidiaries;
+
+               coding.eol_type = default_buffer_file_coding.eol_type;
+               subsidiaries = Fget (coding.symbol, Qeol_type);
+               if (VECTORP (subsidiaries)
+                   && XVECTOR (subsidiaries)->size == 3)
+                 coding.symbol
+                   = XVECTOR (subsidiaries)->contents[coding.eol_type];
              }
-           val = Qnil;
          }
+
+       if (force_raw_text)
+         setup_raw_text_coding_system (&coding);
+       goto done_setup_coding;
       }
-    else
-      {
-       Lisp_Object args[7], coding_systems;
-
-       args[0] = Qwrite_region; args[1] = start; args[2] = end;
-       args[3] = filename; args[4] = append; args[5] = visit;
-       args[6] = lockname;
-       coding_systems = Ffind_operation_coding_system (7, args);
-       val = (CONSP (coding_systems) && !NILP (XCONS (coding_systems)->cdr)
-              ? XCONS (coding_systems)->cdr
-              : current_buffer->buffer_file_coding_system);
-       /* Confirm that VAL can surely encode the current region.  */
-       if (!NILP (Ffboundp (Vselect_safe_coding_system_function)))
-         val = call3 (Vselect_safe_coding_system_function, start, end, val);
-      }
-    setup_coding_system (Fcheck_coding_system (val), &coding); 
+
+    setup_coding_system (Fcheck_coding_system (val), &coding);
 
   done_setup_coding:
     if (!STRINGP (start) && !NILP (current_buffer->selective_display))
@@ -4120,7 +4447,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   filename = Fexpand_file_name (filename, Qnil);
 
-  if (! NILP (confirm))
+  if (! NILP (mustbenew) && mustbenew != Qexcl)
     barf_or_query_if_file_exists (filename, "overwrite", 1, 0, 1);
 
   if (STRINGP (visit))
@@ -4200,9 +4527,9 @@ to the file, instead of any buffer contents, and END is ignored.")
   desc = -1;
   if (!NILP (append))
 #ifdef DOS_NT
-    desc = open (fn, O_WRONLY | buffer_file_type);
+    desc = emacs_open (fn, O_WRONLY | buffer_file_type, 0);
 #else  /* not DOS_NT */
-    desc = open (fn, O_WRONLY);
+    desc = emacs_open (fn, O_WRONLY, 0);
 #endif /* not DOS_NT */
 
   if (desc < 0 && (NILP (append) || errno == ENOENT))
@@ -4210,7 +4537,7 @@ to the file, instead of any buffer contents, and END is ignored.")
     if (auto_saving)    /* Overwrite any previous version of autosave file */
       {
        vms_truncate (fn);      /* if fn exists, truncate to zero length */
-       desc = open (fn, O_RDWR);
+       desc = emacs_open (fn, O_RDWR, 0);
        if (desc < 0)
          desc = creat_copy_attrs (STRINGP (current_buffer->filename)
                                   ? XSTRING (current_buffer->filename)->data : 0,
@@ -4243,7 +4570,7 @@ to the file, instead of any buffer contents, and END is ignored.")
                    /* We can't make a new version;
                       try to truncate and rewrite existing version if any.  */
                    vms_truncate (fn);
-                   desc = open (fn, O_RDWR);
+                   desc = emacs_open (fn, O_RDWR, 0);
                  }
 #endif
              }
@@ -4253,11 +4580,14 @@ to the file, instead of any buffer contents, and END is ignored.")
       }
 #else /* not VMS */
 #ifdef DOS_NT
-  desc = open (fn,
-              O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type,
-              S_IREAD | S_IWRITE);
+  desc = emacs_open (fn,
+                    O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type
+                    | (mustbenew == Qexcl ? O_EXCL : 0),
+                    S_IREAD | S_IWRITE);
 #else  /* not DOS_NT */
-  desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
+  desc = emacs_open (fn, O_WRONLY | O_TRUNC | O_CREAT
+                    | (mustbenew == Qexcl ? O_EXCL : 0),
+                    auto_saving ? auto_save_mode_bits : 0666);
 #endif /* not DOS_NT */
 #endif /* not VMS */
 
@@ -4275,7 +4605,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   record_unwind_protect (close_file_unwind, make_number (desc));
 
-  if (!NILP (append))
+  if (!NILP (append) && !NILP (Ffile_regular_p (filename)))
     if (lseek (desc, 0, 2) < 0)
       {
 #ifdef CLASH_DETECTION
@@ -4402,7 +4732,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 #endif
 
   /* NFS can report a write failure now.  */
-  if (close (desc) < 0)
+  if (emacs_close (desc) < 0)
     failure = 1, save_errno = errno;
 
 #ifdef VMS
@@ -4436,7 +4766,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   if (failure)
     error ("IO error writing %s: %s", XSTRING (filename)->data,
-          strerror (save_errno));
+          emacs_strerror (save_errno));
 
   if (visiting)
     {
@@ -4622,13 +4952,22 @@ e_write (desc, addr, nbytes, coding)
      now it is handled within encode_coding.  */
   while (1)
     {
-      encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
+      int result;
+
+      result = encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
       nbytes -= coding->consumed, addr += coding->consumed;
       if (coding->produced > 0)
        {
-         coding->produced -= write (desc, buf, coding->produced);
+         coding->produced -= emacs_write (desc, buf, coding->produced);
          if (coding->produced) return -1;
        }
+      if (result == CODING_FINISH_INSUFFICIENT_SRC)
+       {
+         /* The source text ends by an incomplete multibyte form.
+             There's no way other than write it out as is.  */
+         nbytes -= emacs_write (desc, addr, nbytes);
+         if (nbytes) return -1;
+       }
       if (nbytes <= 0)
        break;
     }
@@ -4775,8 +5114,8 @@ do_auto_save_unwind (stream)  /* used as unwind-protect function */
 {
   auto_saving = 0;
   if (!NILP (stream))
-    fclose ((FILE *) (XFASTINT (XCONS (stream)->car) << 16
-                     | XFASTINT (XCONS (stream)->cdr)));
+    fclose ((FILE *) (XFASTINT (XCAR (stream)) << 16
+                     | XFASTINT (XCDR (stream))));
   return Qnil;
 }
 
@@ -4804,9 +5143,6 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
   struct buffer *old = current_buffer, *b;
   Lisp_Object tail, buf;
   int auto_saved = 0;
-  char *omessage = echo_area_glyphs;
-  int omessage_length = echo_area_glyphs_length;
-  int oldmultibyte = message_enable_multibyte;
   int do_handled_files;
   Lisp_Object oquit;
   FILE *stream;
@@ -4814,7 +5150,8 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
   int count = specpdl_ptr - specpdl;
   int *ptr;
   int orig_minibuffer_auto_raise = minibuffer_auto_raise;
-
+  int message_p = push_message ();
+  
   /* Ordinarily don't quit within this function,
      but don't make it impossible to quit (in case we get hung in I/O).  */
   oquit = Vquit_flag;
@@ -4839,8 +5176,8 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
          /* Arrange to close that file whether or not we get an error.
             Also reset auto_saving to 0.  */
          lispstream = Fcons (Qnil, Qnil);
-         XSETFASTINT (XCONS (lispstream)->car, (EMACS_UINT)stream >> 16);
-         XSETFASTINT (XCONS (lispstream)->cdr, (EMACS_UINT)stream & 0xffff);
+         XSETFASTINT (XCAR (lispstream), (EMACS_UINT)stream >> 16);
+         XSETFASTINT (XCDR (lispstream), (EMACS_UINT)stream & 0xffff);
        }
       else
        lispstream = Qnil;
@@ -4863,9 +5200,9 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
      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 = XCONS (tail)->cdr)
+    for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
       {
-       buf = XCONS (XCONS (tail)->car)->cdr;
+       buf = XCDR (XCAR (tail));
        b = XBUFFER (buf);
 
        /* Record all the buffers that have auto save mode
@@ -4958,10 +5295,10 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
 
   if (auto_saved && NILP (no_message))
     {
-      if (omessage)
+      if (message_p)
        {
          sit_for (1, 0, 0, 0, 0);
-         message2 (omessage, omessage_length, oldmultibyte);
+         restore_message ();
        }
       else
        message1 ("Auto-saving...done");
@@ -4969,6 +5306,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
 
   Vquit_flag = oquit;
 
+  pop_message ();
   unbind_to (count, Qnil);
   return Qnil;
 }
@@ -5127,7 +5465,7 @@ DIR defaults to current buffer's directory default.")
   (prompt, dir, default_filename, mustmatch, initial)
      Lisp_Object prompt, dir, default_filename, mustmatch, initial;
 {
-  Lisp_Object val, insdef, insdef1, tem;
+  Lisp_Object val, insdef, tem;
   struct gcpro gcpro1, gcpro2;
   register char *homedir;
   int replace_in_history = 0;
@@ -5159,6 +5497,22 @@ DIR defaults to current buffer's directory default.")
                         STRING_BYTES (XSTRING (dir)) - strlen (homedir) + 1);
       XSTRING (dir)->data[0] = '~';
     }
+  /* Likewise for default_filename.  */
+  if (homedir != 0
+      && STRINGP (default_filename)
+      && !strncmp (homedir, XSTRING (default_filename)->data, strlen (homedir))
+      && IS_DIRECTORY_SEP (XSTRING (default_filename)->data[strlen (homedir)]))
+    {
+      default_filename
+       = make_string (XSTRING (default_filename)->data + strlen (homedir) - 1,
+                      STRING_BYTES (XSTRING (default_filename)) - strlen (homedir) + 1);
+      XSTRING (default_filename)->data[0] = '~';
+    }
+  if (!NILP (default_filename))
+    {
+      CHECK_STRING (default_filename, 3);
+      default_filename = double_dollars (default_filename);
+    }
 
   if (insert_default_directory && STRINGP (dir))
     {
@@ -5171,31 +5525,41 @@ DIR defaults to current buffer's directory default.")
          args[1] = initial;
          insdef = Fconcat (2, args);
          pos = make_number (XSTRING (double_dollars (dir))->size);
-         insdef1 = Fcons (double_dollars (insdef), pos);
+         insdef = Fcons (double_dollars (insdef), pos);
        }
       else
-       insdef1 = double_dollars (insdef);
+       insdef = double_dollars (insdef);
     }
   else if (STRINGP (initial))
-    {
-      insdef = initial;
-      insdef1 = Fcons (double_dollars (insdef), make_number (0));
-    }
+    insdef = Fcons (double_dollars (initial), make_number (0));
   else
-    insdef = Qnil, insdef1 = Qnil;
+    insdef = Qnil;
 
-#ifdef VMS
   count = specpdl_ptr - specpdl;
+#ifdef VMS
   specbind (intern ("completion-ignore-case"), Qt);
 #endif
 
+  specbind (intern ("minibuffer-completing-file-name"), Qt);
+
   GCPRO2 (insdef, default_filename);
-  val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
-                         dir, mustmatch, insdef1,
-                         Qfile_name_history, default_filename, Qnil);
+  
+#ifdef USE_MOTIF
+  if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
+      && use_dialog_box
+      && have_menus_p ())
+    {
+      val = Fx_file_dialog (prompt, dir, default_filename, mustmatch);
+      add_to_history = 1;
+    }
+  else
+#endif
+    val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
+                           dir, mustmatch, insdef,
+                           Qfile_name_history, default_filename, Qnil);
 
   tem = Fsymbol_value (Qfile_name_history);
-  if (CONSP (tem) && EQ (XCONS (tem)->car, val))
+  if (CONSP (tem) && EQ (XCAR (tem), val))
     replace_in_history = 1;
 
   /* If Fcompleting_read returned the inserted default string itself
@@ -5213,15 +5577,12 @@ DIR defaults to current buffer's directory default.")
       val = build_string ("");
     }
 
-#ifdef VMS
   unbind_to (count, Qnil);
-#endif
-
   UNGCPRO;
   if (NILP (val))
     error ("No file name specified");
 
-  tem = Fstring_equal (val, insdef);
+  tem = Fstring_equal (val, CONSP (insdef) ? XCAR (insdef) : insdef);
 
   if (!NILP (tem) && !NILP (default_filename))
     val = default_filename;
@@ -5237,18 +5598,29 @@ DIR defaults to current buffer's directory default.")
   if (replace_in_history)
     /* Replace what Fcompleting_read added to the history
        with what we will actually return.  */
-    XCONS (Fsymbol_value (Qfile_name_history))->car = val;
+    XCAR (Fsymbol_value (Qfile_name_history)) = double_dollars (val);
   else if (add_to_history)
     {
       /* Add the value to the history--but not if it matches
         the last value already there.  */
+      Lisp_Object val1 = double_dollars (val);
       tem = Fsymbol_value (Qfile_name_history);
-      if (! CONSP (tem) || NILP (Fequal (XCONS (tem)->car, val)))
+      if (! CONSP (tem) || NILP (Fequal (XCAR (tem), val1)))
        Fset (Qfile_name_history,
-             Fcons (val, tem));
+             Fcons (val1, tem));
     }
+    
   return val;
 }
+
+\f
+void
+init_fileio_once ()
+{
+  /* Must be set before any path manipulation is performed.  */
+  XSETFASTINT (Vdirectory_sep_char, '/');
+}
+
 \f
 void
 syms_of_fileio ()
@@ -5325,6 +5697,8 @@ syms_of_fileio ()
   staticpro (&Qfile_already_exists);
   Qfile_date_error = intern ("file-date-error");
   staticpro (&Qfile_date_error);
+  Qexcl = intern ("excl");
+  staticpro (&Qexcl);
 
 #ifdef DOS_NT
   Qfind_buffer_file_type = intern ("find-buffer-file-type");
@@ -5394,7 +5768,6 @@ The value should be either ?/ or ?\\ (any other value is treated as ?\\).\n\
 This variable affects the built-in functions only on Windows,\n\
 on other platforms, it is initialized so that Lisp code can find out\n\
 what the normal separator is.");
-  XSETFASTINT (Vdirectory_sep_char, '/');
 
   DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
     "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
@@ -5414,9 +5787,11 @@ for its argument.");
   DEFVAR_LISP ("set-auto-coding-function",
               &Vset_auto_coding_function,
     "If non-nil, a function to call to decide a coding system of file.\n\
-One argument is passed to this function: the string of concatination\n\
-or the heading 1K-byte and the tailing 3K-byte of a file to be read.\n\
-This function should return a coding system to decode the file contents\n\
+Two arguments are passed to this function: the file name\n\
+and the length of a file contents following the point.\n\
+This function should return a coding system to decode the file contents.\n\
+It should check the file name against `auto-coding-alist'.\n\
+If no coding system is decided, it should check a coding system\n\
 specified in the heading lines with the format:\n\
        -*- ... coding: CODING-SYSTEM; ... -*-\n\
 or local variable spec of the tailing lines with `coding:' tag.");