(Qforeground_color, Qbackground_color): Declare.
[bpt/emacs.git] / src / fileio.c
index 3d74758..25f4ea6 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985,86,87,88,93,94,95,96,1997 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,88,93,94,95,96,97,1998 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -159,6 +159,13 @@ int auto_saving;
    a new file with the same mode as the original */
 int auto_save_mode_bits;
 
+/* Coding system for file names, or nil if none.  */
+Lisp_Object Vfile_name_coding_system;
+
+/* Coding system for file names used only when
+   Vfile_name_coding_system is nil.  */
+Lisp_Object Vdefault_file_name_coding_system;
+
 /* Alist of elements (REGEXP . HANDLER) for file names
    whose I/O is done with a special handler.  */
 Lisp_Object Vfile_name_handler_alist;
@@ -170,7 +177,7 @@ Lisp_Object Vauto_save_file_format;
 Lisp_Object Qformat_decode, Qformat_annotate_function;
 
 /* Function to be called to decide a coding system of a reading file.  */
-Lisp_Object Vauto_file_coding_system_function;
+Lisp_Object Vset_auto_coding_function;
 
 /* Functions to be called to process text properties in inserted file.  */
 Lisp_Object Vafter_insert_file_functions;
@@ -219,6 +226,11 @@ Lisp_Object Qfile_name_history;
 
 Lisp_Object Qcar_less_than_car;
 
+static int a_write P_ ((int, char *, int, int,
+                       Lisp_Object *, struct coding_system *));
+static int e_write P_ ((int, char *, int, struct coding_system *));
+\f
+void
 report_file_error (string, data)
      char *string;
      Lisp_Object data;
@@ -237,19 +249,23 @@ report_file_error (string, data)
             Fcons (build_string (string), Fcons (errstring, data)));
 }
 
+Lisp_Object
 close_file_unwind (fd)
      Lisp_Object fd;
 {
   close (XFASTINT (fd));
+  return Qnil;
 }
 
 /* Restore point, having saved it as a marker.  */
 
+static Lisp_Object
 restore_point_unwind (location)
      Lisp_Object location;
 {
-  SET_PT (marker_position (location));
+  Fgoto_char (location);
   Fset_marker (location, Qnil, Qnil);
+  return Qnil;
 }
 \f
 Lisp_Object Qexpand_file_name;
@@ -359,7 +375,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
 #ifdef DOS_NT
   beg = strcpy (alloca (strlen (beg) + 1), beg);
 #endif
-  p = beg + XSTRING (filename)->size;
+  p = beg + STRING_BYTES (XSTRING (filename));
 
   while (p != beg && !IS_DIRECTORY_SEP (p[-1])
 #ifdef VMS
@@ -389,11 +405,14 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.")
     }
   CORRECT_DIR_SEPS (beg);
 #endif /* DOS_NT */
-  return make_string (beg, p - beg);
+
+  if (STRING_MULTIBYTE (filename))
+    return make_string (beg, p - beg);
+  return make_unibyte_string (beg, p - beg);
 }
 
-DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory,
-  1, 1, 0,
+DEFUN ("file-name-nondirectory", Ffile_name_nondirectory,
+       Sfile_name_nondirectory, 1, 1, 0,
   "Return file name FILENAME sans its directory.\n\
 For example, in a Unix-syntax file name,\n\
 this is everything after the last slash,\n\
@@ -413,7 +432,7 @@ or the entire name if it contains no slash.")
     return call2 (handler, Qfile_name_nondirectory, filename);
 
   beg = XSTRING (filename)->data;
-  end = p = beg + XSTRING (filename)->size;
+  end = p = beg + STRING_BYTES (XSTRING (filename));
 
   while (p != beg && !IS_DIRECTORY_SEP (p[-1])
 #ifdef VMS
@@ -423,17 +442,21 @@ or the entire name if it contains no slash.")
         /* only recognise drive specifier at beginning */
         && !(p[-1] == ':' && p == beg + 2)
 #endif
-        ) p--;
+        )
+    p--;
 
-  return make_string (p, end - p);
+  if (STRING_MULTIBYTE (filename))
+    return make_string (p, end - p);
+  return make_unibyte_string (p, end - p);
 }
 
-DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory, Sunhandled_file_name_directory, 1, 1, 0,
+DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory,
+       Sunhandled_file_name_directory, 1, 1, 0,
   "Return a directly usable directory name somehow associated with FILENAME.\n\
 A `directly usable' directory name is one that may be used without the\n\
 intervention of any file handler.\n\
 If FILENAME is a directly usable file itself, return\n\
-(file-name-directory FILENAME).\n\
+\(file-name-directory FILENAME).\n\
 The `call-process' and `start-process' functions use this function to\n\
 get a current directory to run processes in.")
   (filename)
@@ -459,6 +482,14 @@ file_name_as_directory (out, in)
 
   strcpy (out, in);
 
+  if (size < 0)
+    {
+      out[0] = '.';
+      out[1] = '/';
+      out[2] = 0;
+      return out;
+    }
+
 #ifdef VMS
   /* Is it already a directory string? */
   if (in[size] == ':' || in[size] == ']' || in[size] == '>')
@@ -555,7 +586,7 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
   if (!NILP (handler))
     return call2 (handler, Qfile_name_as_directory, file);
 
-  buf = (char *) alloca (XSTRING (file)->size + 10);
+  buf = (char *) alloca (STRING_BYTES (XSTRING (file)) + 10);
   return build_string (file_name_as_directory (buf, XSTRING (file)->data));
 }
 \f
@@ -569,6 +600,7 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
  * Value is nonzero if the string output is different from the input.
  */
 
+int
 directory_file_name (src, dst)
      char *src, *dst;
 {
@@ -750,9 +782,9 @@ it returns a file name such as \"[X]Y.DIR.1\".")
   /* 20 extra chars is insufficient for VMS, since we might perform a
      logical name translation. an equivalence string can be up to 255
      chars long, so grab that much extra space...  - sss */
-  buf = (char *) alloca (XSTRING (directory)->size + 20 + 255);
+  buf = (char *) alloca (STRING_BYTES (XSTRING (directory)) + 20 + 255);
 #else
-  buf = (char *) alloca (XSTRING (directory)->size + 20);
+  buf = (char *) alloca (STRING_BYTES (XSTRING (directory)) + 20);
 #endif
   directory_file_name (XSTRING (directory)->data, buf);
   return build_string (buf);
@@ -761,10 +793,13 @@ it returns a file name such as \"[X]Y.DIR.1\".")
 DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
   "Generate temporary file name (string) starting with PREFIX (a string).\n\
 The Emacs process number forms part of the result,\n\
-so there is no danger of generating a name being used by another process.")
+so there is no danger of generating a name being used by another process.\n\
+In addition, this function makes an attempt to choose a name\n\
+which has no existing file.")
   (prefix)
      Lisp_Object prefix;
 {
+  char *temp;
   Lisp_Object val;
 #ifdef MSDOS
   /* Don't use too many characters of the restricted 8+3 DOS
@@ -773,7 +808,10 @@ so there is no danger of generating a name being used by another process.")
 #else
   val = concat2 (prefix, build_string ("XXXXXX"));
 #endif
-  mktemp (XSTRING (val)->data);
+  temp = mktemp (XSTRING (val)->data);
+  if (! temp)
+    error ("No temporary file names based on %s are available",
+          XSTRING (prefix)->data);
 #ifdef DOS_NT
   CORRECT_DIR_SEPS (XSTRING (val)->data);
 #endif
@@ -792,7 +830,7 @@ file names in the file system.\n\
 An initial `~/' expands to your home directory.\n\
 An initial `~USER/' expands to USER's home directory.\n\
 See also the function `substitute-in-file-name'.")
-     (name, default_directory)
+  (name, default_directory)
      Lisp_Object name, default_directory;
 {
   unsigned char *nm;
@@ -827,7 +865,8 @@ See also the function `substitute-in-file-name'.")
   /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted.  */
   if (NILP (default_directory))
     default_directory = current_buffer->directory;
-  CHECK_STRING (default_directory, 1);
+  if (! STRINGP (default_directory))
+    default_directory = build_string ("/");
 
   if (!NILP (default_directory))
     {
@@ -915,6 +954,14 @@ See also the function `substitute-in-file-name'.")
              goto look_again;
        }
   }
+
+#ifdef WINDOWSNT
+  /* If we see "c://somedir", we want to strip the first slash after the
+     colon when stripping the drive letter.  Otherwise, this expands to
+     "//somedir".  */
+  if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
+    nm++;
+#endif /* WINDOWSNT */
 #endif /* DOS_NT */
 
 #ifdef WINDOWSNT
@@ -1232,7 +1279,7 @@ See also the function `substitute-in-file-name'.")
        }
 
       /* Keep only a prefix from newdir if nm starts with slash
-         (//server/share for UNC, nothing otherwise). */
+         (//server/share for UNC, nothing otherwise).  */
       if (IS_DIRECTORY_SEP (nm[0]) && collapse_newdir)
        {
 #ifdef WINDOWSNT
@@ -1255,7 +1302,7 @@ 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 // (an incomplete UNC name).  */
       length = strlen (newdir);
       if (length > 0 && IS_DIRECTORY_SEP (newdir[length - 1])
 #ifdef WINDOWSNT
@@ -1356,17 +1403,6 @@ See also the function `substitute-in-file-name'.")
        {
          *o++ = *p++;
        }
-      else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
-#if defined (APOLLO) || defined (WINDOWSNT)
-              /* // at start of filename is meaningful in Apollo
-                 and WindowsNT systems */
-              && o != target
-#endif /* APOLLO || WINDOWSNT */
-              )
-       {
-         o = target;
-         p++;
-       }
       else if (IS_DIRECTORY_SEP (p[0])
               && p[1] == '.'
               && (IS_DIRECTORY_SEP (p[2])
@@ -1454,7 +1490,7 @@ See also the function `substitute-in-file-name'.")
   nm = XSTRING (name)->data;
 
   /* If nm is absolute, flush ...// and detect /./ and /../.
-     If no /./ or /../ we can return right away. */
+     If no /./ or /../ we can return right away.  */
   if (
       nm[0] == '/'
 #ifdef VMS
@@ -1468,7 +1504,7 @@ See also the function `substitute-in-file-name'.")
        {
          if (p[0] == '/' && p[1] == '/'
 #ifdef APOLLO
-             /* // at start of filename is meaningful on Apollo system */
+             /* // at start of filename is meaningful on Apollo system */
              && nm != p
 #endif /* APOLLO */
              )
@@ -1701,7 +1737,7 @@ See also the function `substitute-in-file-name'.")
        }
       else if (!strncmp (p, "//", 2)
 #ifdef APOLLO
-              /* // at start of filename is meaningful in Apollo system */
+              /* // at start of filename is meaningful in Apollo system */
               && o != target
 #endif /* APOLLO */
               )
@@ -1775,16 +1811,16 @@ duplicates what `expand-file-name' does.")
   CORRECT_DIR_SEPS (nm);
   substituted = (strcmp (nm, XSTRING (filename)->data) != 0);
 #endif
-  endp = nm + XSTRING (filename)->size;
+  endp = nm + STRING_BYTES (XSTRING (filename));
 
-  /* If /~ or // appears, discard everything through first slash. */
+  /* If /~ or // appears, discard everything through first slash.  */
 
   for (p = nm; p != endp; p++)
     {
       if ((p[0] == '~'
 #if defined (APOLLO) || defined (WINDOWSNT)
           /* // at start of file name is meaningful in Apollo and
-             WindowsNT systems */
+             WindowsNT systems */
           || (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm)
 #else /* not (APOLLO || WINDOWSNT) */
           || IS_DIRECTORY_SEP (p[0])
@@ -1868,7 +1904,7 @@ duplicates what `expand-file-name' does.")
 
   /* If substitution required, recopy the string and do it */
   /* Make space in stack frame for the new copy */
-  xnm = (unsigned char *) alloca (XSTRING (filename)->size + total + 1);
+  xnm = (unsigned char *) alloca (STRING_BYTES (XSTRING (filename)) + total + 1);
   x = xnm;
 
   /* Copy the rest of the name through, replacing $ constructs with values */
@@ -1912,13 +1948,37 @@ duplicates what `expand-file-name' does.")
        if (!o)
          goto badvar;
 
-       strcpy (x, o);
-       x += strlen (o);
+       if (STRING_MULTIBYTE (filename))
+         {
+           /* If the original string is multibyte,
+              convert what we substitute into multibyte.  */
+           unsigned char workbuf[4], *str;
+           int len;
+
+           while (*o)
+             {
+               int c = *o++;
+               c = unibyte_char_to_multibyte (c);
+               if (! SINGLE_BYTE_CHAR_P (c))
+                 {
+                   len = CHAR_STRING (c, workbuf, str);
+                   bcopy (str, x, len);
+                   x += len;
+                 }
+               else
+                 *x++ = c;
+             }
+         }
+       else
+         {
+           strcpy (x, o);
+           x += strlen (o);
+         }
       }
 
   *x = 0;
 
-  /* If /~ or // appears, discard everything through first slash. */
+  /* If /~ or // appears, discard everything through first slash.  */
 
   for (p = xnm; p != x; p++)
     if ((p[0] == '~'
@@ -1936,7 +1996,9 @@ duplicates what `expand-file-name' does.")
       xnm = p;
 #endif
 
-  return make_string (xnm, x - xnm);
+  if (STRING_MULTIBYTE (filename))
+    return make_string (xnm, x - xnm);
+  return make_unibyte_string (xnm, x - xnm);
 
  badsubst:
   error ("Bad format environment-variable substitution");
@@ -1961,7 +2023,7 @@ expand_and_dir_to_file (filename, defdir)
   absname = Fexpand_file_name (filename, defdir);
 #ifdef VMS
   {
-    register int c = XSTRING (absname)->data[XSTRING (absname)->size - 1];
+    register int c = XSTRING (absname)->data[STRING_BYTES (XSTRING (absname)) - 1];
     if (c == ':' || c == ']' || c == '>')
       absname = Fdirectory_file_name (absname);
   }
@@ -1969,8 +2031,8 @@ expand_and_dir_to_file (filename, defdir)
   /* Remove final slash, if any (unless this is the root dir).
      stat behaves differently depending!  */
   if (XSTRING (absname)->size > 1
-      && IS_DIRECTORY_SEP (XSTRING (absname)->data[XSTRING (absname)->size - 1])
-      && !IS_DEVICE_SEP (XSTRING (absname)->data[XSTRING (absname)->size-2]))
+      && IS_DIRECTORY_SEP (XSTRING (absname)->data[STRING_BYTES (XSTRING (absname)) - 1])
+      && !IS_DEVICE_SEP (XSTRING (absname)->data[STRING_BYTES (XSTRING (absname))-2]))
     /* We cannot take shortcuts; they might be wrong for magic file names.  */
     absname = Fdirectory_file_name (absname);
 #endif
@@ -1982,15 +2044,20 @@ expand_and_dir_to_file (filename, defdir)
    and bypass the error if the user says to go ahead.
    QUERYSTRING is a name for the action that is being considered
    to alter the file.
+
    *STATPTR is used to store the stat information if the file exists.
-   If the file does not exist, STATPTR->st_mode is set to 0.  */
+   If the file does not exist, STATPTR->st_mode is set to 0.
+   If STATPTR is null, we don't store into it.
+
+   If QUICK is nonzero, we ask for y or n, not yes or no.  */
 
 void
-barf_or_query_if_file_exists (absname, querystring, interactive, statptr)
+barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
      Lisp_Object absname;
      unsigned char *querystring;
      int interactive;
      struct stat *statptr;
+     int quick;
 {
   register Lisp_Object tem;
   struct stat statbuf;
@@ -2005,8 +2072,12 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr)
                 Fcons (build_string ("File already exists"),
                        Fcons (absname, Qnil)));
       GCPRO1 (absname);
-      tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
-                                    XSTRING (absname)->data, querystring));
+      tem = format1 ("File %s already exists; %s anyway? ",
+                    XSTRING (absname)->data, querystring);
+      if (quick)
+       tem = Fy_or_n_p (tem);
+      else
+       tem = do_yes_or_no_p (tem);
       UNGCPRO;
       if (NILP (tem))
        Fsignal (Qfile_already_exists,
@@ -2040,13 +2111,16 @@ A prefix arg makes KEEP-TIME non-nil.")
   char buf[16 * 1024];
   struct stat st, out_st;
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   int count = specpdl_ptr - specpdl;
   int input_file_statable_p;
+  Lisp_Object encoded_file, encoded_newname;
 
-  GCPRO2 (file, newname);
+  encoded_file = encoded_newname = Qnil;
+  GCPRO4 (file, newname, encoded_file, encoded_newname);
   CHECK_STRING (file, 0);
   CHECK_STRING (newname, 1);
+
   file = Fexpand_file_name (file, Qnil);
   newname = Fexpand_file_name (newname, Qnil);
 
@@ -2060,14 +2134,17 @@ A prefix arg makes KEEP-TIME non-nil.")
     RETURN_UNGCPRO (call5 (handler, Qcopy_file, file, newname,
                           ok_if_already_exists, keep_date));
 
+  encoded_file = ENCODE_FILE (file);
+  encoded_newname = ENCODE_FILE (newname);
+
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
-    barf_or_query_if_file_exists (newname, "copy to it",
-                                 INTEGERP (ok_if_already_exists), &out_st);
-  else if (stat (XSTRING (newname)->data, &out_st) < 0)
+    barf_or_query_if_file_exists (encoded_newname, "copy to it",
+                                 INTEGERP (ok_if_already_exists), &out_st, 0);
+  else if (stat (XSTRING (encoded_newname)->data, &out_st) < 0)
     out_st.st_mode = 0;
 
-  ifd = open (XSTRING (file)->data, O_RDONLY);
+  ifd = open (XSTRING (encoded_file)->data, O_RDONLY);
   if (ifd < 0)
     report_file_error ("Opening input file", Fcons (file, Qnil));
 
@@ -2103,13 +2180,13 @@ A prefix arg makes KEEP-TIME non-nil.")
 
 #ifdef VMS
   /* Create the copy file with the same record format as the input file */
-  ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
+  ofd = sys_creat (XSTRING (encoded_newname)->data, 0666, ifd);
 #else
 #ifdef MSDOS
   /* System's default file type was set to binary by _fmode in emacs.c.  */
-  ofd = creat (XSTRING (newname)->data, S_IREAD | S_IWRITE);
+  ofd = creat (XSTRING (encoded_newname)->data, S_IREAD | S_IWRITE);
 #else /* not MSDOS */
-  ofd = creat (XSTRING (newname)->data, 0666);
+  ofd = creat (XSTRING (encoded_newname)->data, 0666);
 #endif /* not MSDOS */
 #endif /* VMS */
   if (ofd < 0)
@@ -2135,13 +2212,14 @@ A prefix arg makes KEEP-TIME non-nil.")
          EMACS_TIME atime, mtime;
          EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
          EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
-         if (set_file_times (XSTRING (newname)->data, atime, mtime))
+         if (set_file_times (XSTRING (encoded_newname)->data,
+                             atime, mtime))
            Fsignal (Qfile_date_error,
                     Fcons (build_string ("Cannot set file date"),
                            Fcons (newname, Qnil)));
        }
 #ifndef MSDOS
-      chmod (XSTRING (newname)->data, st.st_mode & 07777);
+      chmod (XSTRING (encoded_newname)->data, st.st_mode & 07777);
 #else /* MSDOS */
 #if defined (__DJGPP__) && __DJGPP__ > 1
       /* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
@@ -2149,7 +2227,7 @@ A prefix arg makes KEEP-TIME non-nil.")
          get only the READ bit, which will make the copied file read-only,
          so it's better not to chmod at all.  */
       if ((_djstat_flags & _STFAIL_WRITEBIT) == 0)
-       chmod (XSTRING (newname)->data, st.st_mode & 07777);
+       chmod (XSTRING (encoded_newname)->data, st.st_mode & 07777);
 #endif /* DJGPP version 2 or newer */
 #endif /* MSDOS */
     }
@@ -2171,6 +2249,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
 {
   unsigned char *dir;
   Lisp_Object handler;
+  Lisp_Object encoded_dir;
 
   CHECK_STRING (directory, 0);
   directory = Fexpand_file_name (directory, Qnil);
@@ -2179,7 +2258,9 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
   if (!NILP (handler))
     return call2 (handler, Qmake_directory_internal, directory);
 
-  dir = XSTRING (directory)->data;
+  encoded_dir = ENCODE_FILE (directory);
+
+  dir = XSTRING (encoded_dir)->data;
 
 #ifdef WINDOWSNT
   if (mkdir (dir) != 0)
@@ -2198,15 +2279,19 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
 {
   unsigned char *dir;
   Lisp_Object handler;
+  Lisp_Object encoded_dir;
 
   CHECK_STRING (directory, 0);
   directory = Fdirectory_file_name (Fexpand_file_name (directory, Qnil));
-  dir = XSTRING (directory)->data;
 
   handler = Ffind_file_name_handler (directory, Qdelete_directory);
   if (!NILP (handler))
     return call2 (handler, Qdelete_directory, directory);
 
+  encoded_dir = ENCODE_FILE (directory);
+
+  dir = XSTRING (encoded_dir)->data;
+
   if (rmdir (dir) != 0)
     report_file_error ("Removing directory", Flist (1, &directory));
 
@@ -2220,6 +2305,8 @@ If file has multiple names, it continues to exist with the other names.")
      Lisp_Object filename;
 {
   Lisp_Object handler;
+  Lisp_Object encoded_file;
+
   CHECK_STRING (filename, 0);
   filename = Fexpand_file_name (filename, Qnil);
 
@@ -2227,7 +2314,9 @@ If file has multiple names, it continues to exist with the other names.")
   if (!NILP (handler))
     return call2 (handler, Qdelete_file, filename);
 
-  if (0 > unlink (XSTRING (filename)->data))
+  encoded_file = ENCODE_FILE (filename);
+
+  if (0 > unlink (XSTRING (encoded_file)->data))
     report_file_error ("Removing old name", Flist (1, &filename));
   return Qnil;
 }
@@ -2264,9 +2353,11 @@ This is what happens in interactive use with M-x.")
   Lisp_Object args[2];
 #endif
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  Lisp_Object encoded_file, encoded_newname;
 
-  GCPRO2 (file, newname);
+  encoded_file = encoded_newname = Qnil;
+  GCPRO4 (file, newname, encoded_file, encoded_newname);
   CHECK_STRING (file, 0);
   CHECK_STRING (newname, 1);
   file = Fexpand_file_name (file, Qnil);
@@ -2281,15 +2372,18 @@ This is what happens in interactive use with M-x.")
     RETURN_UNGCPRO (call4 (handler, Qrename_file,
                           file, newname, ok_if_already_exists));
 
+  encoded_file = ENCODE_FILE (file);
+  encoded_newname = ENCODE_FILE (newname);
+
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
-    barf_or_query_if_file_exists (newname, "rename to it",
-                                 INTEGERP (ok_if_already_exists), 0);
+    barf_or_query_if_file_exists (encoded_newname, "rename to it",
+                                 INTEGERP (ok_if_already_exists), 0, 0);
 #ifndef BSD4_1
-  if (0 > rename (XSTRING (file)->data, XSTRING (newname)->data))
+  if (0 > rename (XSTRING (encoded_file)->data, XSTRING (encoded_newname)->data))
 #else
-  if (0 > link (XSTRING (file)->data, XSTRING (newname)->data)
-      || 0 > unlink (XSTRING (file)->data))
+  if (0 > link (XSTRING (encoded_file)->data, XSTRING (encoded_newname)->data)
+      || 0 > unlink (XSTRING (encoded_file)->data))
 #endif
     {
       if (errno == EXDEV)
@@ -2329,9 +2423,11 @@ This is what happens in interactive use with M-x.")
   Lisp_Object args[2];
 #endif
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2;
+  Lisp_Object encoded_file, encoded_newname;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
-  GCPRO2 (file, newname);
+  GCPRO4 (file, newname, encoded_file, encoded_newname);
+  encoded_file = encoded_newname = Qnil;
   CHECK_STRING (file, 0);
   CHECK_STRING (newname, 1);
   file = Fexpand_file_name (file, Qnil);
@@ -2351,17 +2447,16 @@ This is what happens in interactive use with M-x.")
     RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, file,
                           newname, ok_if_already_exists));
 
+  encoded_file = ENCODE_FILE (file);
+  encoded_newname = ENCODE_FILE (newname);
+
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
-    barf_or_query_if_file_exists (newname, "make it a new name",
-                                 INTEGERP (ok_if_already_exists), 0);
-#ifdef WINDOWSNT
-  /* Windows does not support this operation.  */
-  report_file_error ("Adding new name", Flist (2, &file));
-#else /* not WINDOWSNT */
+    barf_or_query_if_file_exists (encoded_newname, "make it a new name",
+                                 INTEGERP (ok_if_already_exists), 0, 0);
 
   unlink (XSTRING (newname)->data);
-  if (0 > link (XSTRING (file)->data, XSTRING (newname)->data))
+  if (0 > link (XSTRING (encoded_file)->data, XSTRING (encoded_newname)->data))
     {
 #ifdef NO_ARG_ARRAY
       args[0] = file;
@@ -2371,7 +2466,6 @@ This is what happens in interactive use with M-x.")
       report_file_error ("Adding new name", Flist (2, &file));
 #endif
     }
-#endif /* not WINDOWSNT */
 
   UNGCPRO;
   return Qnil;
@@ -2392,9 +2486,11 @@ This happens for interactive use with M-x.")
   Lisp_Object args[2];
 #endif
   Lisp_Object handler;
-  struct gcpro gcpro1, gcpro2;
+  Lisp_Object encoded_filename, encoded_linkname;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
-  GCPRO2 (filename, linkname);
+  GCPRO4 (filename, linkname, encoded_filename, encoded_linkname);
+  encoded_filename = encoded_linkname = Qnil;
   CHECK_STRING (filename, 0);
   CHECK_STRING (linkname, 1);
   /* If the link target has a ~, we must expand it to get
@@ -2418,17 +2514,22 @@ This happens for interactive use with M-x.")
     RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
                           linkname, ok_if_already_exists));
 
+  encoded_filename = ENCODE_FILE (filename);
+  encoded_linkname = ENCODE_FILE (linkname);
+
   if (NILP (ok_if_already_exists)
       || INTEGERP (ok_if_already_exists))
-    barf_or_query_if_file_exists (linkname, "make it a link",
-                                 INTEGERP (ok_if_already_exists), 0);
-  if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
+    barf_or_query_if_file_exists (encoded_linkname, "make it a link",
+                                 INTEGERP (ok_if_already_exists), 0, 0);
+  if (0 > symlink (XSTRING (encoded_filename)->data,
+                  XSTRING (encoded_linkname)->data))
     {
       /* If we didn't complain already, silently delete existing file.  */
       if (errno == EEXIST)
        {
-         unlink (XSTRING (linkname)->data);
-         if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
+         unlink (XSTRING (encoded_linkname)->data);
+         if (0 <= symlink (XSTRING (encoded_filename)->data,
+                           XSTRING (encoded_linkname)->data))
            {
              UNGCPRO;
              return Qnil;
@@ -2601,6 +2702,8 @@ See also `file-readable-p' and `file-attributes'.")
   if (!NILP (handler))
     return call2 (handler, Qfile_exists_p, absname);
 
+  absname = ENCODE_FILE (absname);
+
   return (stat (XSTRING (absname)->data, &statbuf) >= 0) ? Qt : Qnil;
 }
 
@@ -2623,6 +2726,8 @@ For a directory, this means you can access files in that directory.")
   if (!NILP (handler))
     return call2 (handler, Qfile_executable_p, absname);
 
+  absname = ENCODE_FILE (absname);
+
   return (check_executable (XSTRING (absname)->data) ? Qt : Qnil);
 }
 
@@ -2647,6 +2752,8 @@ See also `file-exists-p' and `file-attributes'.")
   if (!NILP (handler))
     return call2 (handler, Qfile_readable_p, absname);
 
+  absname = ENCODE_FILE (absname);
+
 #ifdef DOS_NT
   /* Under MS-DOS and Windows, open does not work for directories.  */
   if (access (XSTRING (absname)->data, 0) == 0)
@@ -2679,7 +2786,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
   (filename)
      Lisp_Object filename;
 {
-  Lisp_Object absname, dir;
+  Lisp_Object absname, dir, encoded;
   Lisp_Object handler;
   struct stat statbuf;
 
@@ -2692,9 +2799,11 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
   if (!NILP (handler))
     return call2 (handler, Qfile_writable_p, absname);
 
-  if (stat (XSTRING (absname)->data, &statbuf) >= 0)
-    return (check_writable (XSTRING (absname)->data)
+  encoded = ENCODE_FILE (absname);
+  if (stat (XSTRING (encoded)->data, &statbuf) >= 0)
+    return (check_writable (XSTRING (encoded)->data)
            ? Qt : Qnil);
+
   dir = Ffile_name_directory (absname);
 #ifdef VMS
   if (!NILP (dir))
@@ -2704,6 +2813,8 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
   if (!NILP (dir))
     dir = Fdirectory_file_name (dir);
 #endif /* MSDOS */
+
+  dir = ENCODE_FILE (dir);
   return (check_writable (!NILP (dir) ? (char *) XSTRING (dir)->data : "")
          ? Qt : Qnil);
 }
@@ -2715,7 +2826,7 @@ If there is no error, we return nil.")
   (filename, string)
      Lisp_Object filename, string;
 {
-  Lisp_Object handler;
+  Lisp_Object handler, encoded_filename;
   int fd;
 
   CHECK_STRING (filename, 0);
@@ -2726,7 +2837,9 @@ If there is no error, we return nil.")
   if (!NILP (handler))
     return call3 (handler, Qaccess_file, filename, string);
 
-  fd = open (XSTRING (filename)->data, O_RDONLY);
+  encoded_filename = ENCODE_FILE (filename);
+
+  fd = open (XSTRING (encoded_filename)->data, O_RDONLY);
   if (fd < 0)
     report_file_error (XSTRING (string)->data, Fcons (filename, Qnil));
   close (fd);
@@ -2757,6 +2870,8 @@ Otherwise returns nil.")
   if (!NILP (handler))
     return call2 (handler, Qfile_symlink_p, filename);
 
+  filename = ENCODE_FILE (filename);
+
   bufsize = 100;
   while (1)
     {
@@ -2775,6 +2890,7 @@ Otherwise returns nil.")
     }
   val = make_string (buf, valsize);
   xfree (buf);
+  val = DECODE_FILE (val);
   return val;
 #else /* not S_IFLNK */
   return Qnil;
@@ -2798,6 +2914,8 @@ DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
   if (!NILP (handler))
     return call2 (handler, Qfile_directory_p, absname);
 
+  absname = ENCODE_FILE (absname);
+
   if (stat (XSTRING (absname)->data, &st) < 0)
     return Qnil;
   return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
@@ -2854,6 +2972,8 @@ This is the sort of file that holds an ordinary stream of data bytes.")
   if (!NILP (handler))
     return call2 (handler, Qfile_regular_p, absname);
 
+  absname = ENCODE_FILE (absname);
+
   if (stat (XSTRING (absname)->data, &st) < 0)
     return Qnil;
   return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil;
@@ -2876,6 +2996,8 @@ DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
   if (!NILP (handler))
     return call2 (handler, Qfile_modes, absname);
 
+  absname = ENCODE_FILE (absname);
+
   if (stat (XSTRING (absname)->data, &st) < 0)
     return Qnil;
 #if defined (MSDOS) && __DJGPP__ < 2
@@ -2892,7 +3014,7 @@ Only the 12 low bits of MODE are used.")
   (filename, mode)
      Lisp_Object filename, mode;
 {
-  Lisp_Object absname;
+  Lisp_Object absname, encoded_absname;
   Lisp_Object handler;
 
   absname = Fexpand_file_name (filename, current_buffer->directory);
@@ -2904,7 +3026,9 @@ Only the 12 low bits of MODE are used.")
   if (!NILP (handler))
     return call3 (handler, Qset_file_modes, absname, mode);
 
-  if (chmod (XSTRING (absname)->data, XINT (mode)) < 0)
+  encoded_absname = ENCODE_FILE (absname);
+
+  if (chmod (XSTRING (encoded_absname)->data, XINT (mode)) < 0)
     report_file_error ("Doing chmod", Fcons (absname, Qnil));
 
   return Qnil;
@@ -2981,6 +3105,11 @@ otherwise, if FILE2 does not exist, the answer is t.")
   if (!NILP (handler))
     return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
 
+  GCPRO2 (absname1, absname2);
+  absname1 = ENCODE_FILE (absname1);
+  absname2 = ENCODE_FILE (absname2);
+  UNGCPRO;
+
   if (stat (XSTRING (absname1)->data, &st) < 0)
     return Qnil;
 
@@ -3003,13 +3132,14 @@ Lisp_Object Qfind_buffer_file_type;
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
   1, 5, 0,
   "Insert contents of file FILENAME after point.\n\
-Returns list of absolute file name and length of data inserted.\n\
+Returns list of absolute file name and number of bytes inserted.\n\
 If second argument VISIT is non-nil, the buffer's visited filename\n\
 and last save file modtime are set, and it is marked unmodified.\n\
 If visiting and the file does not exist, visiting is completed\n\
 before the error is signaled.\n\
 The optional third and fourth arguments BEG and END\n\
 specify what portion of the file to insert.\n\
+These arguments count bytes in the file, not characters in the buffer.\n\
 If VISIT is non-nil, BEG and END must be nil.\n\
 \n\
 If optional fifth argument REPLACE is non-nil,\n\
@@ -3028,12 +3158,12 @@ This does code conversion according to the value of\n\
 {
   struct stat st;
   register int fd;
-  register int inserted = 0;
+  int inserted = 0;
   register int how_much;
   register int unprocessed;
   int count = specpdl_ptr - specpdl;
-  struct gcpro gcpro1, gcpro2, gcpro3;
-  Lisp_Object handler, val, insval;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  Lisp_Object handler, val, insval, orig_filename;
   Lisp_Object p;
   int total;
   int not_regular = 0;
@@ -3041,6 +3171,7 @@ This does code conversion according to the value of\n\
   struct coding_system coding;
   unsigned char buffer[1 << 14];
   int replace_handled = 0;
+  int set_coding_system = 0;
 
   if (current_buffer->base_buffer && ! NILP (visit))
     error ("Cannot do file visiting in an indirect buffer");
@@ -3050,8 +3181,9 @@ This does code conversion according to the value of\n\
 
   val = Qnil;
   p = Qnil;
+  orig_filename = Qnil;
 
-  GCPRO3 (filename, val, p);
+  GCPRO4 (filename, val, p, orig_filename);
 
   CHECK_STRING (filename, 0);
   filename = Fexpand_file_name (filename, Qnil);
@@ -3066,6 +3198,9 @@ This does code conversion according to the value of\n\
       goto handled;
     }
 
+  orig_filename = filename;
+  filename = ENCODE_FILE (filename);
+
   fd = -1;
 
 #ifndef APOLLO
@@ -3078,9 +3213,11 @@ This does code conversion according to the value of\n\
       if (fd >= 0) close (fd);
     badopen:
       if (NILP (visit))
-       report_file_error ("Opening input file", Fcons (filename, Qnil));
+       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;
       goto notfound;
     }
 
@@ -3098,7 +3235,7 @@ This does code conversion according to the value of\n\
       if (! NILP (replace) || ! NILP (beg) || ! NILP (end))
        Fsignal (Qfile_error,
                 Fcons (build_string ("not a regular file"),
-                       Fcons (filename, Qnil)));
+                       Fcons (orig_filename, Qnil)));
     }
 #endif
 
@@ -3143,42 +3280,70 @@ This does code conversion according to the value of\n\
 
     if (!NILP (Vcoding_system_for_read))
       val = Vcoding_system_for_read;
-    else if (NILP (current_buffer->enable_multibyte_characters))
-      val = Qemacs_mule;
     else
       {
-       if (SYMBOLP (Vauto_file_coding_system_function)
-           && Fboundp (Vauto_file_coding_system_function))
+       if (! NILP (Vset_auto_coding_function))
          {
-           /* Find a coding system specified in a few lines at the
-              head of the file.  We assume that the fist 1K bytes is
-              sufficient fot this purpose.  */
-           int nread = read (fd, read_buf, 1024);
+           /* 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 (filename)->data, strerror (errno));
+                    XSTRING (orig_filename)->data, strerror (errno));
            else if (nread > 0)
              {
-               val = call1 (Vauto_file_coding_system_function,
-                            make_string (read_buf, nread));
+               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 (filename, Qnil));
+                                    Fcons (orig_filename, Qnil));
              }
          }
        if (NILP (val))
          {
            Lisp_Object args[6], coding_systems;
 
-           args[0] = Qinsert_file_contents, args[1] = filename,
+           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;
          }
       }
-    setup_coding_system (Fcheck_coding_system (val), &coding);
+
+    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;
+
+       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 requested, replace the accessible part of the buffer
@@ -3196,10 +3361,13 @@ 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_MAY_REQUIRE_NO_CONVERSION (&coding))
+      && ! CODING_REQUIRE_DECODING (&coding))
     {
-      int same_at_start = BEGV;
-      int same_at_end = ZV;
+      /* same_at_start and same_at_end count bytes,
+        because file access counts bytes
+        and BEG and END count bytes.  */
+      int same_at_start = BEGV_BYTE;
+      int same_at_end = ZV_BYTE;
       int overlap;
       /* There is still a possibility we will find the need to do code
         conversion.  If that happens, we set this variable to 1 to
@@ -3210,7 +3378,7 @@ This does code conversion according to the value of\n\
        {
          if (lseek (fd, XINT (beg), 0) < 0)
            report_file_error ("Setting file position",
-                              Fcons (filename, Qnil));
+                              Fcons (orig_filename, Qnil));
        }
 
       immediate_quit = 1;
@@ -3224,15 +3392,13 @@ This does code conversion according to the value of\n\
          nread = read (fd, buffer, sizeof buffer);
          if (nread < 0)
            error ("IO error reading %s: %s",
-                  XSTRING (filename)->data, strerror (errno));
+                  XSTRING (orig_filename)->data, strerror (errno));
          else if (nread == 0)
            break;
 
          if (coding.type == coding_type_undecided)
            detect_coding (&coding, buffer, nread);
-         if (coding.type != coding_type_undecided
-             && coding.type != coding_type_no_conversion
-             && coding.type != coding_type_emacs_mule)
+         if (CODING_REQUIRE_DECODING (&coding))
            /* We found that the file should be decoded somehow.
                Let's give up here.  */
            {
@@ -3252,7 +3418,7 @@ This does code conversion according to the value of\n\
            }
 
          bufpos = 0;
-         while (bufpos < nread && same_at_start < ZV
+         while (bufpos < nread && same_at_start < ZV_BYTE
                 && FETCH_BYTE (same_at_start) == buffer[bufpos])
            same_at_start++, bufpos++;
          /* If we found a discrepancy, stop the scan.
@@ -3263,7 +3429,7 @@ This does code conversion according to the value of\n\
       immediate_quit = 0;
       /* If the file matches the buffer completely,
         there's no need to replace anything.  */
-      if (same_at_start - BEGV == XINT (end))
+      if (same_at_start - BEGV_BYTE == XINT (end))
        {
          close (fd);
          specpdl_ptr--;
@@ -3281,7 +3447,7 @@ This does code conversion according to the value of\n\
          int total_read, nread, bufpos, curpos, trial;
 
          /* At what file position are we now scanning?  */
-         curpos = XINT (end) - (ZV - same_at_end);
+         curpos = XINT (end) - (ZV_BYTE - same_at_end);
          /* If the entire file matches the buffer tail, stop the scan.  */
          if (curpos == 0)
            break;
@@ -3289,7 +3455,7 @@ This does code conversion according to the value of\n\
          trial = min (curpos, sizeof buffer);
          if (lseek (fd, curpos - trial, 0) < 0)
            report_file_error ("Setting file position",
-                              Fcons (filename, Qnil));
+                              Fcons (orig_filename, Qnil));
 
          total_read = 0;
          while (total_read < trial)
@@ -3297,7 +3463,7 @@ This does code conversion according to the value of\n\
              nread = read (fd, buffer + total_read, trial - total_read);
              if (nread <= 0)
                error ("IO error reading %s: %s",
-                      XSTRING (filename)->data, strerror (errno));
+                      XSTRING (orig_filename)->data, strerror (errno));
              total_read += nread;
            }
          /* Scan this bufferful from the end, comparing with
@@ -3318,7 +3484,7 @@ This does code conversion according to the value of\n\
              if (same_at_end > same_at_start
                  && FETCH_BYTE (same_at_end - 1) >= 0200
                  && ! NILP (current_buffer->enable_multibyte_characters)
-                 && ! CODING_REQUIRE_NO_CONVERSION (&coding))
+                 && (CODING_MAY_REQUIRE_DECODING (&coding)))
                giveup_match_end = 1;
              break;
            }
@@ -3327,26 +3493,31 @@ This does code conversion according to the value of\n\
 
       if (! giveup_match_end)
        {
+         int temp;
+
          /* We win!  We can handle REPLACE the optimized way.  */
 
          /* Extends the end of non-matching text area to multibyte
              character boundary.  */
          if (! NILP (current_buffer->enable_multibyte_characters))
-           while (same_at_end < ZV && ! CHAR_HEAD_P (POS_ADDR (same_at_end)))
+           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 - (same_at_end + st.st_size - ZV);
+         overlap = (same_at_start - BEGV_BYTE
+                    - (same_at_end + st.st_size - ZV));
          if (overlap > 0)
            same_at_end += overlap;
 
          /* Arrange to read only the nonmatching middle part of the file.  */
-         XSETFASTINT (beg, XINT (beg) + (same_at_start - BEGV));
-         XSETFASTINT (end, XINT (end) - (ZV - same_at_end));
+         XSETFASTINT (beg, XINT (beg) + (same_at_start - BEGV_BYTE));
+         XSETFASTINT (end, XINT (end) - (ZV_BYTE - same_at_end));
 
-         del_range_1 (same_at_start, same_at_end, 0);
+         del_range_byte (same_at_start, same_at_end, 0);
          /* Insert from the file at the proper position.  */
-         SET_PT (same_at_start);
+         temp = BYTE_TO_CHAR (same_at_start);
+         SET_PT_BOTH (temp, same_at_start);
 
          /* If display currently starts at beginning of line,
             keep it that way.  */
@@ -3368,13 +3539,14 @@ This does code conversion according to the value of\n\
      in a more optimized way.  */
   if (!NILP (replace) && ! replace_handled)
     {
-      int same_at_start = BEGV;
-      int same_at_end = ZV;
+      int same_at_start = BEGV_BYTE;
+      int same_at_end = ZV_BYTE;
       int overlap;
       int bufpos;
       /* Make sure that the gap is large enough.  */
       int bufsize = 2 * st.st_size;
       unsigned char *conversion_buffer = (unsigned char *) xmalloc (bufsize);
+      int temp;
 
       /* First read the whole file, performing code conversion into
         CONVERSION_BUFFER.  */
@@ -3383,7 +3555,7 @@ This does code conversion according to the value of\n\
        {
          free (conversion_buffer);
          report_file_error ("Setting file position",
-                            Fcons (filename, Qnil));
+                            Fcons (orig_filename, Qnil));
        }
 
       total = st.st_size;      /* Total bytes in the file.  */
@@ -3412,9 +3584,9 @@ This does code conversion according to the value of\n\
 
          how_much += this;
 
-         if (! CODING_REQUIRE_NO_CONVERSION (&coding))
+         if (CODING_MAY_REQUIRE_DECODING (&coding))
            {
-             int require, produced, consumed;
+             int require, result;
 
              this += unprocessed;
 
@@ -3429,22 +3601,21 @@ This does code conversion according to the value of\n\
 
              /* Convert this batch with results in CONVERSION_BUFFER.  */
              if (how_much >= total)  /* This is the last block.  */
-               coding.last_block = 1;
-             produced = decode_coding (&coding, read_buf,
-                                       conversion_buffer + inserted,
-                                       this, bufsize - inserted,
-                                       &consumed);
+               coding.mode |= CODING_MODE_LAST_BLOCK;
+             result = decode_coding (&coding, read_buf,
+                                     conversion_buffer + inserted,
+                                     this, bufsize - inserted);
 
              /* Save for next iteration whatever we didn't convert.  */
-             unprocessed = this - consumed;
-             bcopy (read_buf + consumed, read_buf, unprocessed);
-             this = produced;
+             unprocessed = this - coding.consumed;
+             bcopy (read_buf + coding.consumed, read_buf, unprocessed);
+             this = coding.produced;
            }
 
          inserted += this;
        }
 
-      /* At this point, INSERTED is how many characters
+      /* At this point, INSERTED is how many characters (i.e. bytes)
         are present in CONVERSION_BUFFER.
         HOW_MUCH should equal TOTAL,
         or should be <= 0 if we couldn't read the file.  */
@@ -3455,7 +3626,7 @@ This does code conversion according to the value of\n\
 
          if (how_much == -1)
            error ("IO error reading %s: %s",
-                  XSTRING (filename)->data, strerror (errno));
+                  XSTRING (orig_filename)->data, strerror (errno));
          else if (how_much == -2)
            error ("maximum buffer size exceeded");
        }
@@ -3492,7 +3663,7 @@ This does code conversion according to the value of\n\
        same_at_end--, bufpos--;
 
       /* Don't try to reuse the same piece of text twice.  */
-      overlap = same_at_start - BEGV - (same_at_end + inserted - ZV);
+      overlap = same_at_start - BEGV_BYTE - (same_at_end + inserted - ZV_BYTE);
       if (overlap > 0)
        same_at_end += overlap;
 
@@ -3504,11 +3675,12 @@ This does code conversion according to the value of\n\
       /* 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 - same_at_end) + (same_at_start - BEG);
-      move_gap (same_at_start);
-      del_range_1 (same_at_start, same_at_end, 0);
-      SET_PT (same_at_start);
-      insert_1 (conversion_buffer + same_at_start - BEG, inserted, 0, 0);
+      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);
+
+      insert_1 (conversion_buffer + same_at_start - BEG_BYTE, inserted,
+               0, 0, 0);
 
       free (conversion_buffer);
       close (fd);
@@ -3542,38 +3714,49 @@ This does code conversion according to the value of\n\
   if (XINT (beg) != 0 || !NILP (replace))
     {
       if (lseek (fd, XINT (beg), 0) < 0)
-       report_file_error ("Setting file position", Fcons (filename, Qnil));
+       report_file_error ("Setting file position",
+                          Fcons (orig_filename, Qnil));
     }
 
   /* In the following loop, HOW_MUCH contains the total bytes read so
-     far.  Before exiting the loop, it is set to -1 if I/O error
-     occurs, set to -2 if the maximum buffer size is exceeded.  */
+     far for a regular file, and not changed for a special file.  But,
+     before exiting the loop, it is set to a negative value if I/O
+     error occurs.  */
   how_much = 0;
   /* Total bytes inserted.  */
   inserted = 0;
-  /* Bytes not processed in the previous loop because short gap size.  */
-  unprocessed = 0;
+  /* Here, we don't do code conversion in the loop.  It is done by
+     code_convert_region after all data are read into the buffer.  */
   while (how_much < total)
     {
        /* try is reserved in some compilers (Microsoft C) */
-      int trytry = min (total - how_much, READ_BUF_SIZE - unprocessed);
-      char *destination = (CODING_REQUIRE_NO_CONVERSION (&coding)
-                          ? (char *) (POS_ADDR (PT + inserted - 1) + 1)
-                          : read_buf + unprocessed);
+      int trytry = min (total - how_much, READ_BUF_SIZE);
       int this;
 
+      /* For a special file, GAP_SIZE should be checked every time.  */
+      if (not_regular && GAP_SIZE < trytry)
+       make_gap (total - GAP_SIZE);
+
       /* Allow quitting out of the actual I/O.  */
       immediate_quit = 1;
       QUIT;
-      this = read (fd, destination, trytry);
+      this = read (fd, BYTE_POS_ADDR (PT_BYTE + inserted - 1) + 1, trytry);
       immediate_quit = 0;
 
-      if (this < 0 || this + unprocessed == 0)
+      if (this <= 0)
        {
          how_much = this;
          break;
        }
 
+      GAP_SIZE -= this;
+      GPT_BYTE += this;
+      ZV_BYTE += this;
+      Z_BYTE += this;
+      GPT += this;
+      ZV += this;
+      Z += this;
+
       /* For a regular file, where TOTAL is the real size,
         count HOW_MUCH to compare with it.
         For a special file, where TOTAL is just a buffer size,
@@ -3581,116 +3764,64 @@ This does code conversion according to the value of\n\
         (INSERTED is where we count the number of characters inserted.)  */
       if (! not_regular)
        how_much += this;
-
-      if (! CODING_REQUIRE_NO_CONVERSION (&coding))
-       {
-         int require, produced, consumed;
-
-         this += unprocessed;
-         /* Make sure that the gap is large enough.  */
-         require = decoding_buffer_size (&coding, this);
-         if (GAP_SIZE < require)
-           make_gap (require - GAP_SIZE);
-
-         if (! not_regular)
-           {
-             if (how_much >= total)  /* This is the last block.  */
-               coding.last_block = 1;
-           }
-         else
-           {
-             /* If we encounter EOF, say it is the last block.  (The
-                data this will apply to is the UNPROCESSED characters
-                carried over from the last batch.)  */
-             if (this == 0)
-               coding.last_block = 1;
-           }
-
-         produced = decode_coding (&coding, read_buf,
-                                   POS_ADDR (PT + inserted - 1) + 1,
-                                   this, GAP_SIZE, &consumed);
-         if (produced > 0) 
-           {
-             Lisp_Object temp;
-
-             XSET (temp, Lisp_Int, Z + produced);
-             if (Z + produced != XINT (temp))
-               {
-                 how_much = -2;
-                 break;
-               }
-           }
-         unprocessed = this - consumed;
-         bcopy (read_buf + consumed, read_buf, unprocessed);
-         this = produced;
-       }
-
-      GPT += this;
-      GAP_SIZE -= this;
-      ZV += this;
-      Z += this;
-      if (GAP_SIZE > 0)
-       /* Put an anchor to ensure multi-byte form ends at gap.  */
-       *GPT_ADDR = 0;
       inserted += this;
     }
 
+  if (GAP_SIZE > 0)
+    /* Put an anchor to ensure multi-byte form ends at gap.  */
+    *GPT_ADDR = 0;
 
-#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;
-#endif
+  close (fd);
 
-  /* We don't have to consider file type of MSDOS because all files
-     are read as binary and end-of-line format has already been
-     decoded appropriately.  */
-#if 0
-#ifdef DOS_NT
-  /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
-  /* Determine file type from name and remove LFs from CR-LFs if the file
-     is deemed to be a text file.  */
-  {
-    current_buffer->buffer_file_type
-      = call1 (Qfind_buffer_file_type, filename);
-    if (NILP (current_buffer->buffer_file_type))
-      {
-       int reduced_size
-         = inserted - crlf_to_lf (inserted, POS_ADDR (PT - 1) + 1);
-       ZV -= reduced_size;
-       Z -= reduced_size;
-       GPT -= reduced_size;
-       GAP_SIZE += reduced_size;
-       inserted -= reduced_size;
-      }
-  }
-#endif /* DOS_NT */
-#endif /* 0 */
+  /* 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));
 
   if (inserted > 0)
     {
-      record_insert (PT, inserted);
+      if (CODING_MAY_REQUIRE_DECODING (&coding))
+       {
+         /* Here, we don't have to consider byte combining (see the
+             comment below) because code_convert_region takes care of
+             it.  */
+         code_convert_region (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
+                              &coding, 0, 0);
+         inserted = (NILP (current_buffer->enable_multibyte_characters)
+                     ? coding.produced : coding.produced_char);
+       }
+      else if (!NILP (current_buffer->enable_multibyte_characters))
+       {
+         int inserted_byte = inserted;
+
+         /* There's a possibility that we must combine bytes at the
+            head (resp. the tail) of the just inserted text with the
+            bytes before (resp. after) the gap to form a single
+            character.  */
+         inserted = multibyte_chars_in_text (GPT_ADDR - inserted, inserted);
+         adjust_after_insert (PT, PT_BYTE,
+                              PT + inserted_byte, PT_BYTE + inserted_byte,
+                              inserted);
+       }
+      else
+       adjust_after_insert (PT, PT_BYTE, PT + inserted, PT_BYTE + inserted,
+                            inserted);
 
-      /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
-      offset_intervals (current_buffer, PT, inserted);
-      MODIFF++;
+#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;
+#endif
     }
 
-  close (fd);
-
-  /* Discard the unwind protect for closing the file.  */
-  specpdl_ptr--;
-
-  if (how_much == -1)
-    error ("IO error reading %s: %s",
-          XSTRING (filename)->data, strerror (errno));
-  else if (how_much == -2)
-    error ("maximum buffer size exceeded");
+  set_coding_system = 1;
 
  notfound:
  handled:
@@ -3706,7 +3837,7 @@ This does code conversion according to the value of\n\
       if (NILP (handler))
        {
          current_buffer->modtime = st.st_mtime;
-         current_buffer->filename = filename;
+         current_buffer->filename = orig_filename;
        }
 
       SAVE_MODIFF = MODIFF;
@@ -3723,11 +3854,11 @@ This does code conversion according to the value of\n\
       if (not_regular)
        Fsignal (Qfile_error,
                 Fcons (build_string ("not a regular file"),
-                       Fcons (filename, Qnil)));
+                       Fcons (orig_filename, Qnil)));
 
       /* If visiting nonexistent file, return nil.  */
       if (current_buffer->modtime == -1)
-       report_file_error ("Opening input file", Fcons (filename, Qnil));
+       report_file_error ("Opening input file", Fcons (orig_filename, Qnil));
     }
 
   /* Decode file format */
@@ -3746,12 +3877,12 @@ This does code conversion according to the value of\n\
       && (NILP (visit) || !NILP (replace)))
     signal_after_change (PT, 0, inserted);
 
+  if (set_coding_system)
+    Vlast_coding_system_used = coding.symbol;
+
   if (inserted > 0)
     {
       p = Vafter_insert_file_functions;
-      if (!NILP (coding.post_read_conversion))
-       p = Fcons (coding.post_read_conversion, p);
-
       while (!NILP (p))
        {
          insval = call1 (Fcar (p), make_number (inserted));
@@ -3765,16 +3896,17 @@ This does code conversion according to the value of\n\
        }
     }
 
+  /* ??? Retval needs to be dealt with in all cases consistently.  */
   if (NILP (val))
-    val = Fcons (filename,
+    val = Fcons (orig_filename,
                 Fcons (make_number (inserted),
                        Qnil));
 
   RETURN_UNGCPRO (unbind_to (count, val));
 }
 \f
-static Lisp_Object build_annotations ();
-extern Lisp_Object Ffile_locked_p ();
+static Lisp_Object build_annotations P_ ((Lisp_Object, Lisp_Object,
+                                         Lisp_Object));
 
 /* If build_annotations switched buffers, switch back to BUF.
    Kill the temporary buffer that was selected in the meantime.
@@ -3797,8 +3929,8 @@ build_annotations_unwind (buf)
   return Qnil;
 }
 
-DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
-  "r\nFWrite region to file: ",
+DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 7,
+  "r\nFWrite region to file: \ni\ni\ni\np",
   "Write current region into specified file.\n\
 When called from a program, takes three arguments:\n\
 START, END and FILENAME.  START and END are buffer positions.\n\
@@ -3814,10 +3946,12 @@ 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\
 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)
-     Lisp_Object start, end, filename, append, visit, lockname;
+  (start, end, filename, append, visit, lockname, confirm)
+     Lisp_Object start, end, filename, append, visit, lockname, confirm;
 {
   register int desc;
   int failure;
@@ -3833,6 +3967,7 @@ to the file, instead of any buffer contents, and END is ignored.")
   Lisp_Object handler;
   Lisp_Object visit_file;
   Lisp_Object annotations;
+  Lisp_Object encoded_filename;
   int visiting, quietly;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
   struct buffer *given_buffer;
@@ -3849,7 +3984,7 @@ to the file, instead of any buffer contents, and END is ignored.")
 
   GCPRO4 (start, filename, visit, lockname);
 
-  /* Decide the coding-system to be encoded to.  */
+  /* Decide the coding-system to encode the data with.  */
   {
     Lisp_Object val;
 
@@ -3858,27 +3993,61 @@ to the file, instead of any buffer contents, and END is ignored.")
     else if (!NILP (Vcoding_system_for_write))
       val = Vcoding_system_for_write;
     else if (NILP (current_buffer->enable_multibyte_characters))
-      val = (NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil))
-            ? Qnil
-            : Fsymbol_value (Qbuffer_file_coding_system));
+      {
+       /* If the variable `buffer-file-coding-system' is set locally,
+          it means that the file was read with some kind of code
+          conversion or the varialbe is explicitely set by users.  We
+          had better write it out with the same coding system even if
+          `enable-multibyte-characters' is nil.
+
+          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.  */
+       val = current_buffer->buffer_file_coding_system;
+       if (NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil)))
+         {
+           struct coding_system coding_temp;
+
+           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 (Qraw_text, &coding);
+               coding.eol_type = coding_temp.eol_type;
+               goto done_setup_coding;
+             }
+           val = Qnil;
+         }
+      }
     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;
+       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); 
+
+  done_setup_coding:
     if (!STRINGP (start) && !NILP (current_buffer->selective_display))
-      coding.selective = 1;
+      coding.mode |= CODING_MODE_SELECTIVE_DISPLAY;
   }
 
+  Vlast_coding_system_used = coding.symbol;
+
   filename = Fexpand_file_name (filename, Qnil);
+
+  if (! NILP (confirm))
+    barf_or_query_if_file_exists (filename, "overwrite", 1, 0, 1);
+
   if (STRINGP (visit))
     visit_file = Fexpand_file_name (visit, Qnil);
   else
@@ -3950,7 +4119,9 @@ to the file, instead of any buffer contents, and END is ignored.")
     }
 #endif /* CLASH_DETECTION */
 
-  fn = XSTRING (filename)->data;
+  encoded_filename = ENCODE_FILE (filename);
+
+  fn = XSTRING (encoded_filename)->data;
   desc = -1;
   if (!NILP (append))
 #ifdef DOS_NT
@@ -3959,7 +4130,7 @@ to the file, instead of any buffer contents, and END is ignored.")
     desc = open (fn, O_WRONLY);
 #endif /* not DOS_NT */
 
-  if (desc < 0 && (NILP (append) || errno == ENOENT) )
+  if (desc < 0 && (NILP (append) || errno == ENOENT))
 #ifdef VMS
     if (auto_saving)    /* Overwrite any previous version of autosave file */
       {
@@ -4063,7 +4234,12 @@ to the file, instead of any buffer contents, and END is ignored.")
       && coding.type == coding_type_iso2022
       && coding.flags & CODING_FLAG_ISO_DESIGNATE_AT_BOL
       && GPT > BEG && GPT_ADDR[-1] != '\n')
-    move_gap (find_next_newline (GPT, 1));
+    {
+      int opoint = PT, opoint_byte = PT_BYTE;
+      scan_newline (PT, PT_BYTE, ZV, ZV_BYTE, 1, 0);
+      move_gap_both (PT, PT_BYTE);
+      SET_PT_BOTH (opoint, opoint_byte);
+    }
 #endif
 
   failure = 0;
@@ -4072,45 +4248,46 @@ to the file, instead of any buffer contents, and END is ignored.")
   if (STRINGP (start))
     {
       failure = 0 > a_write (desc, XSTRING (start)->data,
-                            XSTRING (start)->size, 0, &annotations, &coding);
+                            STRING_BYTES (XSTRING (start)), 0, &annotations,
+                            &coding);
       save_errno = errno;
     }
   else if (XINT (start) != XINT (end))
     {
-      int nwritten = 0;
+      register int end1 = CHAR_TO_BYTE (XINT (end));
+
+      tem = CHAR_TO_BYTE (XINT (start));
+
       if (XINT (start) < GPT)
        {
-         register int end1 = XINT (end);
-         tem = XINT (start);
-         failure = 0 > a_write (desc, POS_ADDR (tem),
-                                min (GPT, end1) - tem, tem, &annotations,
+         failure = 0 > a_write (desc, BYTE_POS_ADDR (tem),
+                                min (GPT_BYTE, end1) - tem, tem, &annotations,
                                 &coding);
-         nwritten += min (GPT, end1) - tem;
          save_errno = errno;
        }
 
       if (XINT (end) > GPT && !failure)
        {
-         tem = XINT (start);
-         tem = max (tem, GPT);
-         failure = 0 > a_write (desc, POS_ADDR (tem), XINT (end) - tem,
+         tem = max (tem, GPT_BYTE);
+         failure = 0 > a_write (desc, BYTE_POS_ADDR (tem), end1 - tem,
                                 tem, &annotations, &coding);
-         nwritten += XINT (end) - tem;
          save_errno = errno;
        }
     }
   else
     {
       /* If file was empty, still need to write the annotations */
-      coding.last_block = 1;
+      coding.mode |= CODING_MODE_LAST_BLOCK;
       failure = 0 > a_write (desc, "", 0, XINT (start), &annotations, &coding);
       save_errno = errno;
     }
 
-  if (coding.require_flushing && !coding.last_block)
+  if (CODING_REQUIRE_FLUSHING (&coding)
+      && !(coding.mode & CODING_MODE_LAST_BLOCK)
+      && ! failure)
     {
       /* We have to flush out a data. */
-      coding.last_block = 1;
+      coding.mode |= CODING_MODE_LAST_BLOCK;
       failure = 0 > e_write (desc, "", 0, &coding);
       save_errno = errno;
     }
@@ -4183,7 +4360,8 @@ to the file, instead of any buffer contents, and END is ignored.")
     current_buffer->modtime = st.st_mtime;
 
   if (failure)
-    error ("IO error writing %s: %s", fn, strerror (save_errno));
+    error ("IO error writing %s: %s", XSTRING (filename)->data,
+          strerror (save_errno));
 
   if (visiting)
     {
@@ -4196,11 +4374,11 @@ to the file, instead of any buffer contents, and END is ignored.")
     return Qnil;
 
   if (!auto_saving)
-    message ("Wrote %s", XSTRING (visit_file)->data);
+    message_with_string ("Wrote %s", visit_file, 1);
 
   return Qnil;
 }
-
+\f
 Lisp_Object merge ();
 
 DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
@@ -4292,86 +4470,96 @@ build_annotations (start, end, pre_write_conversion)
   UNGCPRO;
   return annotations;
 }
-
-/* Write to descriptor DESC the LEN characters starting at ADDR,
-   assuming they start at position POS in the buffer.
+\f
+/* Write to descriptor DESC the NBYTES bytes starting at ADDR,
+   assuming they start at byte position BYTEPOS in the buffer.
    Intersperse with them the annotations from *ANNOT
-   (those which fall within the range of positions POS to POS + LEN),
+   which fall within the range of byte positions BYTEPOS to BYTEPOS + NBYTES,
    each at its appropriate position.
 
-   Modify *ANNOT by discarding elements as we output them.
+   We modify *ANNOT by discarding elements as we use them up.
+
    The return value is negative in case of system call failure.  */
 
-int
-a_write (desc, addr, len, pos, annot, coding)
+static int
+a_write (desc, addr, nbytes, bytepos, annot, coding)
      int desc;
      register char *addr;
-     register int len;
-     int pos;
+     register int nbytes;
+     int bytepos;
      Lisp_Object *annot;
      struct coding_system *coding;
 {
   Lisp_Object tem;
   int nextpos;
-  int lastpos = pos + len;
+  int lastpos = bytepos + nbytes;
 
   while (NILP (*annot) || CONSP (*annot))
     {
       tem = Fcar_safe (Fcar (*annot));
-      if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos)
-       nextpos = XFASTINT (tem);
-      else
-       return e_write (desc, addr, lastpos - pos, coding);
-      if (nextpos > pos)
+      nextpos = bytepos - 1;
+      if (INTEGERP (tem))
+       nextpos = CHAR_TO_BYTE (XFASTINT (tem));
+
+      /* If there are no more annotations in this range,
+        output the rest of the range all at once.  */
+      if (! (nextpos >= bytepos && nextpos <= lastpos))
+       return e_write (desc, addr, lastpos - bytepos, coding);
+
+      /* Output buffer text up to the next annotation's position.  */
+      if (nextpos > bytepos)
        {
-         if (0 > e_write (desc, addr, nextpos - pos, coding))
+         if (0 > e_write (desc, addr, nextpos - bytepos, coding))
            return -1;
-         addr += nextpos - pos;
-         pos = nextpos;
+         addr += nextpos - bytepos;
+         bytepos = nextpos;
        }
+      /* Output the annotation.  */
       tem = Fcdr (Fcar (*annot));
       if (STRINGP (tem))
        {
-         if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size,
+         if (0 > e_write (desc, XSTRING (tem)->data, STRING_BYTES (XSTRING (tem)),
                           coding))
            return -1;
        }
       *annot = Fcdr (*annot);
     }
+  return 0;
 }
 
 #ifndef WRITE_BUF_SIZE
 #define WRITE_BUF_SIZE (16 * 1024)
 #endif
 
-int
-e_write (desc, addr, len, coding)
+/* Write NBYTES bytes starting at ADDR into descriptor DESC,
+   encoding them with coding system CODING.  */
+
+static int
+e_write (desc, addr, nbytes, coding)
      int desc;
      register char *addr;
-     register int len;
+     register int nbytes;
      struct coding_system *coding;
 {
   char buf[WRITE_BUF_SIZE];
-  int produced, consumed;
 
   /* We used to have a code for handling selective display here.  But,
      now it is handled within encode_coding.  */
   while (1)
     {
-      produced = encode_coding (coding, addr, buf, len, WRITE_BUF_SIZE,
-                               &consumed);
-      len -= consumed, addr += consumed;
-      if (produced > 0)
+      encode_coding (coding, addr, buf, nbytes, WRITE_BUF_SIZE);
+      nbytes -= coding->consumed, addr += coding->consumed;
+      if (coding->produced > 0)
        {
-         produced -= write (desc, buf, produced);
-         if (produced) return -1;
+         coding->produced -= write (desc, buf, coding->produced);
+         if (coding->produced) return -1;
        }
-      if (len <= 0)
+      if (nbytes <= 0)
        break;
     }
   return 0;
 }
-
+\f
 DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
   Sverify_visited_file_modtime, 1, 1, 0,
   "Return t if last mod time of BUF's visited file matches what BUF records.\n\
@@ -4382,6 +4570,7 @@ This means that the file has not been changed since it was visited or saved.")
   struct buffer *b;
   struct stat st;
   Lisp_Object handler;
+  Lisp_Object filename;
 
   CHECK_BUFFER (buf, 0);
   b = XBUFFER (buf);
@@ -4396,7 +4585,9 @@ This means that the file has not been changed since it was visited or saved.")
   if (!NILP (handler))
     return call2 (handler, Qverify_visited_file_modtime, buf);
 
-  if (stat (XSTRING (b->filename)->data, &st) < 0)
+  filename = ENCODE_FILE (b->filename);
+
+  if (stat (XSTRING (filename)->data, &st) < 0)
     {
       /* If the file doesn't exist now and didn't exist before,
         we say that it isn't modified, provided the error is a tame one.  */
@@ -4461,7 +4652,10 @@ An argument specifies the modification time value to use\n\
       if (!NILP (handler))
        /* The handler can find the file name the same way we did.  */
        return call2 (handler, Qset_visited_file_modtime, Qnil);
-      else if (stat (XSTRING (filename)->data, &st) >= 0)
+
+      filename = ENCODE_FILE (filename);
+
+      if (stat (XSTRING (filename)->data, &st) >= 0)
        current_buffer->modtime = st.st_mtime;
     }
 
@@ -4472,11 +4666,11 @@ Lisp_Object
 auto_save_error ()
 {
   ring_bell ();
-  message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
+  message_with_string ("Autosaving...error for %s", current_buffer->name, 1);
   Fsleep_for (make_number (1), Qnil);
-  message ("Autosaving...error!for %s", XSTRING (current_buffer->name)->data);
+  message_with_string ("Autosaving...error for %s", current_buffer->name, 0);
   Fsleep_for (make_number (1), Qnil);
-  message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
+  message_with_string ("Autosaving...error for %s", current_buffer->name, 0);
   Fsleep_for (make_number (1), Qnil);
   return Qnil;
 }
@@ -4497,7 +4691,7 @@ auto_save_1 ()
   return
     Fwrite_region (Qnil, Qnil,
                   current_buffer->auto_save_file_name,
-                  Qnil, Qlambda, Qnil);
+                  Qnil, Qlambda, Qnil, Qnil);
 }
 
 static Lisp_Object
@@ -4537,6 +4731,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
   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;
@@ -4607,11 +4802,11 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
            if (!NILP (b->filename))
              {
                fwrite (XSTRING (b->filename)->data, 1,
-                       XSTRING (b->filename)->size, stream);
+                       STRING_BYTES (XSTRING (b->filename)), stream);
              }
            putc ('\n', stream);
            fwrite (XSTRING (b->auto_save_file_name)->data, 1,
-                   XSTRING (b->auto_save_file_name)->size, stream);
+                   STRING_BYTES (XSTRING (b->auto_save_file_name)), stream);
            putc ('\n', stream);
          }
 
@@ -4656,8 +4851,8 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
              {
                /* It has shrunk too much; turn off auto-saving here.  */
                minibuffer_auto_raise = orig_minibuffer_auto_raise;
-               message ("Buffer %s has shrunk a lot; auto save turned off there",
-                        XSTRING (b->name)->data);
+               message_with_string ("Buffer %s has shrunk a lot; auto save turned off there",
+                                    b->name, 1);
                minibuffer_auto_raise = 0;
                /* Turn off auto-saving until there's a real save,
                   and prevent any more warnings.  */
@@ -4691,7 +4886,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.")
       if (omessage)
        {
          sit_for (1, 0, 0, 0, 0);
-         message2 (omessage, omessage_length);
+         message2 (omessage, omessage_length, oldmultibyte);
        }
       else
        message1 ("Auto-saving...done");
@@ -4745,14 +4940,16 @@ double_dollars (val)
   register int n;
   int osize, count;
 
-  osize = XSTRING (val)->size;
-  /* Quote "$" as "$$" to get it past substitute-in-file-name */
+  osize = STRING_BYTES (XSTRING (val));
+
+  /* Count the number of $ characters.  */
   for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
     if (*old++ == '$') count++;
   if (count > 0)
     {
       old = XSTRING (val)->data;
-      val = Fmake_string (make_number (osize + count), make_number (0));
+      val = make_uninit_multibyte_string (XSTRING (val)->size + count,
+                                         osize + count);
       new = XSTRING (val)->data;
       for (n = osize; n > 0; n--)
        if (*old != '$')
@@ -4858,6 +5055,8 @@ DIR defaults to current buffer's directory default.")
   Lisp_Object val, insdef, insdef1, tem;
   struct gcpro gcpro1, gcpro2;
   register char *homedir;
+  int replace_in_history = 0;
+  int add_to_history = 0;
   int count;
 
   if (NILP (dir))
@@ -4882,7 +5081,7 @@ DIR defaults to current buffer's directory default.")
       && IS_DIRECTORY_SEP (XSTRING (dir)->data[strlen (homedir)]))
     {
       dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
-                        XSTRING (dir)->size - strlen (homedir) + 1);
+                        STRING_BYTES (XSTRING (dir)) - strlen (homedir) + 1);
       XSTRING (dir)->data[0] = '~';
     }
 
@@ -4918,14 +5117,26 @@ DIR defaults to current buffer's directory default.")
   GCPRO2 (insdef, default_filename);
   val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
                          dir, mustmatch, insdef1,
-                         Qfile_name_history, default_filename);
-  /* If Fcompleting_read returned the default string itself
+                         Qfile_name_history, default_filename, Qnil);
+
+  tem = Fsymbol_value (Qfile_name_history);
+  if (CONSP (tem) && EQ (XCONS (tem)->car, val))
+    replace_in_history = 1;
+
+  /* If Fcompleting_read returned the inserted default string itself
      (rather than a new string with the same contents),
      it has to mean that the user typed RET with the minibuffer empty.
      In that case, we really want to return ""
      so that commands such as set-visited-file-name can distinguish.  */
   if (EQ (val, default_filename))
-    val = build_string ("");
+    {
+      /* In this case, Fcompleting_read has not added an element
+        to the history.  Maybe we should.  */
+      if (! replace_in_history)
+       add_to_history = 1;
+
+      val = build_string ("");
+    }
 
 #ifdef VMS
   unbind_to (count, Qnil);
@@ -4934,81 +5145,37 @@ DIR defaults to current buffer's directory default.")
   UNGCPRO;
   if (NILP (val))
     error ("No file name specified");
+
   tem = Fstring_equal (val, insdef);
+
   if (!NILP (tem) && !NILP (default_filename))
-    return default_filename;
-  if (XSTRING (val)->size == 0 && NILP (insdef))
+    val = default_filename;
+  else if (XSTRING (val)->size == 0 && NILP (insdef))
     {
       if (!NILP (default_filename))
-       return default_filename;
+       val = default_filename;
       else
        error ("No default file name");
     }
-  return Fsubstitute_in_file_name (val);
-}
-
-#if 0                           /* Old version */
-DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
-  /* Don't confuse make-docfile by having two doc strings for this function.
-     make-docfile does not pay attention to #if, for good reason!  */
-  0)
-  (prompt, dir, defalt, mustmatch, initial)
-     Lisp_Object prompt, dir, defalt, mustmatch, initial;
-{
-  Lisp_Object val, insdef, tem;
-  struct gcpro gcpro1, gcpro2;
-  register char *homedir;
-  int count;
+  val = Fsubstitute_in_file_name (val);
 
-  if (NILP (dir))
-    dir = current_buffer->directory;
-  if (NILP (defalt))
-    defalt = current_buffer->filename;
-
-  /* If dir starts with user's homedir, change that to ~. */
-  homedir = (char *) egetenv ("HOME");
-  if (homedir != 0
-      && STRINGP (dir)
-      && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
-      && XSTRING (dir)->data[strlen (homedir)] == '/')
+  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;
+  else if (add_to_history)
     {
-      dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
-                        XSTRING (dir)->size - strlen (homedir) + 1);
-      XSTRING (dir)->data[0] = '~';
+      /* Add the value to the history--but not if it matches
+        the last value already there.  */
+      tem = Fsymbol_value (Qfile_name_history);
+      if (! CONSP (tem) || NILP (Fequal (XCONS (tem)->car, val)))
+       Fset (Qfile_name_history,
+             Fcons (val, tem));
     }
-
-  if (!NILP (initial))
-    insdef = initial;
-  else if (insert_default_directory)
-    insdef = dir;
-  else
-    insdef = build_string ("");
-
-#ifdef VMS
-  count = specpdl_ptr - specpdl;
-  specbind (intern ("completion-ignore-case"), Qt);
-#endif
-
-  GCPRO2 (insdef, defalt);
-  val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
-                         dir, mustmatch,
-                         insert_default_directory ? insdef : Qnil,
-                         Qfile_name_history, Qnil);
-
-#ifdef VMS
-  unbind_to (count, Qnil);
-#endif
-
-  UNGCPRO;
-  if (NILP (val))
-    error ("No file name specified");
-  tem = Fstring_equal (val, insdef);
-  if (!NILP (tem) && !NILP (defalt))
-    return defalt;
-  return Fsubstitute_in_file_name (val);
+  return val;
 }
-#endif /* Old version */
 \f
+void
 syms_of_fileio ()
 {
   Qexpand_file_name = intern ("expand-file-name");
@@ -5089,6 +5256,22 @@ syms_of_fileio ()
   staticpro (&Qfind_buffer_file_type);
 #endif /* DOS_NT */
 
+  DEFVAR_LISP ("file-name-coding-system", &Vfile_name_coding_system,
+    "*Coding system for encoding file names.\n\
+If it is nil, default-file-name-coding-system (which see) is used.");
+  Vfile_name_coding_system = Qnil;
+
+  DEFVAR_LISP ("default-file-name-coding-system",
+              &Vdefault_file_name_coding_system,
+    "Default coding system for encoding file names.\n\
+This variable is used only when file-name-coding-system is nil.\n\
+\n\
+This variable is set/changed by the command set-language-environment.\n\
+User should not set this variable manually,\n\
+instead use file-name-coding-system to get a constant encoding\n\
+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,
     "*Format in which to write auto-save files.\n\
 Should be a list of symbols naming formats that are defined in `format-alist'.\n\
@@ -5153,15 +5336,16 @@ The function `find-file-name-handler' checks this list for a handler\n\
 for its argument.");
   Vfile_name_handler_alist = Qnil;
 
-  DEFVAR_LISP ("auto-file-coding-system-function",
-              &Vauto_file_coding_system_function,
+  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 the first\n\
-few lines of a file to be read.\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\
 specified in the heading lines with the format:\n\
-       -*- ... coding: CODING-SYSTEM; ... -*-");
-  Vauto_file_coding_system_function = Qnil;
+       -*- ... coding: CODING-SYSTEM; ... -*-\n\
+or local variable spec of the tailing lines with `coding:' tag.");
+  Vset_auto_coding_function = Qnil;
 
   DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
     "A list of functions to be called at the end of `insert-file-contents'.\n\