(Fset_char_table_parent): Doc fix.
[bpt/emacs.git] / src / fileio.c
index 0b06e4f..9ed4610 100644 (file)
@@ -1,5 +1,5 @@
 /* File IO for GNU Emacs.
-   Copyright (C) 1985,86,87,88,93,94,95,96,97,98,99,2000, 2001
+   Copyright (C) 1985,86,87,88,93,94,95,96,97,98,99,2000,01,2003
      Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -21,7 +21,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 
-#if defined (USG5) || defined (BSD_SYSTEM) || defined (GNU_LINUX)
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
 
@@ -154,6 +154,13 @@ int auto_saving;
    a new file with the same mode as the original */
 int auto_save_mode_bits;
 
+/* The symbol bound to coding-system-for-read when
+   insert-file-contents is called for recovering a file.  This is not
+   an actual coding system name, but just an indicator to tell
+   insert-file-contents to use `emacs-mule' with a special flag for
+   auto saving and recovering a file.  */
+Lisp_Object Qauto_save_coding;
+
 /* Coding system for file names, or nil if none.  */
 Lisp_Object Vfile_name_coding_system;
 
@@ -177,8 +184,13 @@ Lisp_Object Vset_auto_coding_function;
 /* Functions to be called to process text properties in inserted file.  */
 Lisp_Object Vafter_insert_file_functions;
 
+/* Lisp function for setting buffer-file-coding-system and the
+   multibyteness of the current buffer after inserting a file.  */
+Lisp_Object Qafter_insert_file_set_coding;
+
 /* Functions to be called to create text property annotations for file.  */
 Lisp_Object Vwrite_region_annotate_functions;
+Lisp_Object Qwrite_region_annotate_functions;
 
 /* During build_annotations, each time an annotation function is called,
    this holds the annotations made by the previous functions.  */
@@ -188,7 +200,7 @@ Lisp_Object Vwrite_region_annotations_so_far;
 Lisp_Object Vauto_save_list_file_name;
 
 /* Function to call to read a file name.  */
-Lisp_Object Vread_file_name_function; 
+Lisp_Object Vread_file_name_function;
 
 /* Current predicate used by read_file_name_internal.  */
 Lisp_Object Vread_file_name_predicate;
@@ -447,9 +459,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.  */)
   CORRECT_DIR_SEPS (beg);
 #endif /* DOS_NT */
 
-  if (STRING_MULTIBYTE (filename))
-    return make_string (beg, p - beg);
-  return make_unibyte_string (beg, p - beg);
+  return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename));
 }
 
 DEFUN ("file-name-nondirectory", Ffile_name_nondirectory,
@@ -488,9 +498,7 @@ or the entire name if it contains no slash.  */)
         )
     p--;
 
-  if (STRING_MULTIBYTE (filename))
-    return make_string (p, end - p);
-  return make_unibyte_string (p, end - p);
+  return make_specified_string (p, -1, end - p, STRING_MULTIBYTE (filename));
 }
 
 DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory,
@@ -631,7 +639,9 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.  */)
     return call2 (handler, Qfile_name_as_directory, file);
 
   buf = (char *) alloca (SBYTES (file) + 10);
-  return build_string (file_name_as_directory (buf, SDATA (file)));
+  file_name_as_directory (buf, SDATA (file));
+  return make_specified_string (buf, -1, strlen (buf),
+                               STRING_MULTIBYTE (file));
 }
 \f
 /*
@@ -831,7 +841,8 @@ it returns a file name such as \"[X]Y.DIR.1\".  */)
   buf = (char *) alloca (SBYTES (directory) + 20);
 #endif
   directory_file_name (SDATA (directory), buf);
-  return build_string (buf);
+  return make_specified_string (buf, -1, strlen (buf),
+                               STRING_MULTIBYTE (directory));
 }
 
 static char make_temp_name_tbl[64] =
@@ -849,13 +860,13 @@ static char make_temp_name_tbl[64] =
 static unsigned make_temp_name_count, make_temp_name_count_initialized_p;
 
 /* Value is a temporary file name starting with PREFIX, a string.
-   
+
    The Emacs process number forms part of the result, so there is
    no danger of generating a name being used by another process.
    In addition, this function makes an attempt to choose a name
    which has no existing file.  To make this work, PREFIX should be
    an absolute file name.
-   
+
    BASE64_P non-zero means add the pid as 3 characters in base64
    encoding.  In this case, 6 characters will be added to PREFIX to
    form the file name.  Otherwise, if Emacs is running on a system
@@ -875,7 +886,7 @@ make_temp_name (prefix, base64_p)
   unsigned char *p, *data;
   char pidbuf[20];
   int pidlen;
-     
+
   CHECK_STRING (prefix);
 
   /* VAL is created by adding 6 characters to PREFIX.  The first
@@ -904,7 +915,7 @@ make_temp_name (prefix, base64_p)
       pidlen = 3;
 #endif
     }
-  
+
   len = SCHARS (prefix);
   val = make_uninit_string (len + 3 + pidlen);
   data = SDATA (val);
@@ -1027,7 +1038,7 @@ See also the function `substitute-in-file-name'.  */)
   int is_escaped = 0;
 #endif /* DOS_NT */
   int length;
-  Lisp_Object handler;
+  Lisp_Object handler, result;
 
   CHECK_STRING (name);
 
@@ -1195,7 +1206,7 @@ See also the function `substitute-in-file-name'.  */)
                   && IS_DIRECTORY_SEP (p[0])
                   && IS_DIRECTORY_SEP (p[1]))
            lose = 1;
-         
+
 #ifdef VMS
          if (p[0] == '\\')
            lose = 1;
@@ -1275,7 +1286,11 @@ See also the function `substitute-in-file-name'.  */)
        {
 #ifdef VMS
          if (index (nm, '/'))
-           return build_string (sys_translate_unix (nm));
+           {
+             nm = sys_translate_unix (nm);
+             return make_specified_string (nm, -1, strlen (nm),
+                                           STRING_MULTIBYTE (name));
+           }
 #endif /* VMS */
 #ifdef DOS_NT
          /* Make sure directories are all separated with / or \ as
@@ -1286,22 +1301,27 @@ See also the function `substitute-in-file-name'.  */)
          if (IS_DIRECTORY_SEP (nm[1]))
            {
              if (strcmp (nm, SDATA (name)) != 0)
-               name = build_string (nm);
+               name = make_specified_string (nm, -1, strlen (nm),
+                                             STRING_MULTIBYTE (name));
            }
          else
 #endif
          /* drive must be set, so this is okay */
          if (strcmp (nm - 2, SDATA (name)) != 0)
            {
-             name = make_string (nm - 2, p - nm + 2);
-             SSET (name, 0, DRIVE_LETTER (drive));
-             SSET (name, 1, ':');
+             char temp[] = " :";
+
+             name = make_specified_string (nm, -1, p - nm,
+                                           STRING_MULTIBYTE (name));
+             temp[0] = DRIVE_LETTER (drive);
+             name = concat2 (build_string (temp), name);
            }
          return name;
 #else /* not DOS_NT */
          if (nm == SDATA (name))
            return name;
-         return build_string (nm);
+         return make_specified_string (nm, -1, strlen (nm),
+                                       STRING_MULTIBYTE (name));
 #endif /* not DOS_NT */
        }
     }
@@ -1538,7 +1558,7 @@ See also the function `substitute-in-file-name'.  */)
             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]) 
+         if (!(drive && nm[0] && IS_DIRECTORY_SEP (newdir[0])
                && newdir[1] == '\0'))
 #endif
            strcpy (target, newdir);
@@ -1670,7 +1690,19 @@ See also the function `substitute-in-file-name'.  */)
   CORRECT_DIR_SEPS (target);
 #endif /* DOS_NT */
 
-  return make_string (target, o - target);
+  result = make_specified_string (target, -1, o - target,
+                                  STRING_MULTIBYTE (name));
+
+  /* Again look to see if the file name has special constructs in it
+     and perhaps call the corresponding file handler.  This is needed
+     for filenames such as "/foo/../user@host:/bar/../baz".  Expanding
+     the ".." component gives us "/user@host:/bar/../baz" which needs
+     to be expanded again. */
+  handler = Ffind_file_name_handler (result, Qexpand_file_name);
+  if (!NILP (handler))
+    return call3 (handler, Qexpand_file_name, result, default_directory);
+
+  return result;
 }
 
 #if 0
@@ -2052,13 +2084,13 @@ duplicates what `expand-file-name' does.  */)
   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.  */
+#if defined (APOLLO) || defined (WINDOWSNT) || defined(CYGWIN)
+          /* // at start of file name is meaningful in Apollo,
+             WindowsNT and Cygwin systems.  */
           || (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm)
-#else /* not (APOLLO || WINDOWSNT) */
+#else /* not (APOLLO || WINDOWSNT || CYGWIN) */
           || IS_DIRECTORY_SEP (p[0])
-#endif /* not (APOLLO || WINDOWSNT) */
+#endif /* not (APOLLO || WINDOWSNT || CYGWIN) */
           )
          && p != nm
          && (0
@@ -2101,7 +2133,8 @@ duplicates what `expand-file-name' does.  */)
     }
 
 #ifdef VMS
-  return build_string (nm);
+  return make_specified_string (nm, -1, strlen (nm),
+                               STRING_MULTIBYTE (filename));
 #else
 
   /* See if any variables are substituted into the string
@@ -2230,11 +2263,11 @@ duplicates what `expand-file-name' does.  */)
 
   for (p = xnm; p != x; p++)
     if ((p[0] == '~'
-#if defined (APOLLO) || defined (WINDOWSNT)
+#if defined (APOLLO) || defined (WINDOWSNT) || defined(CYGWIN)
         || (IS_DIRECTORY_SEP (p[0]) && p - 1 != xnm)
-#else /* not (APOLLO || WINDOWSNT) */
+#else /* not (APOLLO || WINDOWSNT || CYGWIN) */
         || IS_DIRECTORY_SEP (p[0])
-#endif /* not (APOLLO || WINDOWSNT) */
+#endif /* not (APOLLO || WINDOWSNT || CYGWIN) */
         )
        && p != xnm && IS_DIRECTORY_SEP (p[-1]))
       xnm = p;
@@ -2244,9 +2277,7 @@ duplicates what `expand-file-name' does.  */)
       xnm = p;
 #endif
 
-  if (STRING_MULTIBYTE (filename))
-    return make_string (xnm, x - xnm);
-  return make_unibyte_string (xnm, x - xnm);
+  return make_specified_string (xnm, -1, x - xnm, STRING_MULTIBYTE (filename));
 
  badsubst:
   error ("Bad format environment-variable substitution");
@@ -2323,8 +2354,8 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
                 Fcons (build_string ("File already exists"),
                        Fcons (absname, Qnil)));
       GCPRO1 (absname);
-      tem = format1 ("File %s already exists; %s anyway? ",
-                    SDATA (absname), querystring);
+      tem = format2 ("File %s already exists; %s anyway? ",
+                    absname, build_string (querystring));
       if (quick)
        tem = Fy_or_n_p (tem);
       else
@@ -2355,7 +2386,8 @@ A number as third arg means request confirmation if NEWNAME already exists.
 This is what happens in interactive use with M-x.
 Fourth arg KEEP-TIME non-nil means give the new file the same
 last-modified time as the old one.  (This works on only some systems.)
-A prefix arg makes KEEP-TIME non-nil.  */)
+A prefix arg makes KEEP-TIME non-nil.
+Also set the file modes of the target file to match the source file.  */)
      (file, newname, ok_if_already_exists, keep_time)
      Lisp_Object file, newname, ok_if_already_exists, keep_time;
 {
@@ -2402,10 +2434,11 @@ A prefix arg makes KEEP-TIME non-nil.  */)
 
 #ifdef WINDOWSNT
   if (!CopyFile (SDATA (encoded_file),
-                SDATA (encoded_newname), 
+                SDATA (encoded_newname),
                 FALSE))
     report_file_error ("Copying file", Fcons (file, Fcons (newname, Qnil)));
-  else if (!NILP (keep_time))
+  /* CopyFile retains the timestamp by default.  */
+  else if (NILP (keep_time))
     {
       EMACS_TIME now;
       DWORD attributes;
@@ -2429,7 +2462,10 @@ A prefix arg makes KEEP-TIME non-nil.  */)
       SetFileAttributes (filename, attributes);
     }
 #else /* not WINDOWSNT */
+  immediate_quit = 1;
   ifd = emacs_open (SDATA (encoded_file), O_RDONLY, 0);
+  immediate_quit = 0;
+
   if (ifd < 0)
     report_file_error ("Opening input file", Fcons (file, Qnil));
 
@@ -2559,7 +2595,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
 }
 
 DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
-       doc: /* Delete the directory named DIRECTORY.  */)
+       doc: /* Delete the directory named DIRECTORY.  Does not follow symlinks.  */)
      (directory)
      Lisp_Object directory;
 {
@@ -2585,15 +2621,22 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
 }
 
 DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
-       doc: /* Delete file named FILENAME.
+       doc: /* Delete file named FILENAME.  If it is a symlink, remove the symlink.
 If file has multiple names, it continues to exist with the other names.  */)
      (filename)
      Lisp_Object filename;
 {
   Lisp_Object handler;
   Lisp_Object encoded_file;
+  struct gcpro gcpro1;
 
-  CHECK_STRING (filename);
+  GCPRO1 (filename);
+  if (!NILP (Ffile_directory_p (filename))
+      && NILP (Ffile_symlink_p (filename)))
+    Fsignal (Qfile_error,
+            Fcons (build_string ("Removing old name: is a directory"),
+                   Fcons (filename, Qnil)));
+  UNGCPRO;
   filename = Fexpand_file_name (filename, Qnil);
 
   handler = Ffind_file_name_handler (filename, Qdelete_file);
@@ -3153,16 +3196,11 @@ If there is no error, we return nil.  */)
 \f
 DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
        doc: /* Return non-nil if file FILENAME is the name of a symbolic link.
-The value is the name of the file to which it is linked.
+The value is the link target, as a string.
 Otherwise returns nil.  */)
      (filename)
      Lisp_Object filename;
 {
-#ifdef S_IFLNK
-  char *buf;
-  int bufsize;
-  int valsize;
-  Lisp_Object val;
   Lisp_Object handler;
 
   CHECK_STRING (filename);
@@ -3174,6 +3212,13 @@ Otherwise returns nil.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_symlink_p, filename);
 
+#ifdef S_IFLNK
+  {
+  char *buf;
+  int bufsize;
+  int valsize;
+  Lisp_Object val;
+
   filename = ENCODE_FILE (filename);
 
   bufsize = 50;
@@ -3183,7 +3228,7 @@ Otherwise returns nil.  */)
       bufsize *= 2;
       buf = (char *) xrealloc (buf, bufsize);
       bzero (buf, bufsize);
-      
+
       errno = 0;
       valsize = readlink (SDATA (filename), buf, bufsize);
       if (valsize == -1)
@@ -3201,13 +3246,14 @@ Otherwise returns nil.  */)
        }
     }
   while (valsize >= bufsize);
-  
+
   val = make_string (buf, valsize);
   if (buf[0] == '/' && index (buf, ':'))
     val = concat2 (build_string ("/:"), val);
   xfree (buf);
   val = DECODE_FILE (val);
   return val;
+  }
 #else /* not S_IFLNK */
   return Qnil;
 #endif /* not S_IFLNK */
@@ -3260,12 +3306,6 @@ searchable directory.  */)
   if (!NILP (handler))
     return call2 (handler, Qfile_accessible_directory_p, filename);
 
-  /* It's an unlikely combination, but yes we really do need to gcpro:
-     Suppose that file-accessible-directory-p has no handler, but
-     file-directory-p does have a handler; this handler causes a GC which
-     relocates the string in `filename'; and finally file-directory-p
-     returns non-nil.  Then we would end up passing a garbaged string
-     to file-executable-p.  */
   GCPRO1 (filename);
   tem = (NILP (Ffile_directory_p (filename))
         || NILP (Ffile_executable_p (filename)));
@@ -3527,7 +3567,7 @@ static Lisp_Object
 read_non_regular ()
 {
   int nbytes;
-  
+
   immediate_quit = 1;
   QUIT;
   nbytes = emacs_read (non_regular_fd,
@@ -3551,7 +3591,7 @@ read_non_regular_quit ()
 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
        1, 5, 0,
        doc: /* Insert contents of file FILENAME after point.
-Returns list of absolute file name and number of bytes inserted.
+Returns list of absolute file name and number of characters inserted.
 If second argument VISIT is non-nil, the buffer's visited filename
 and last save file modtime are set, and it is marked unmodified.
 If visiting and the file does not exist, visiting is completed
@@ -3732,7 +3772,20 @@ actually used.  */)
        }
     }
 
-  if (BEG < Z)
+  if (EQ (Vcoding_system_for_read, Qauto_save_coding))
+    {
+      /* We use emacs-mule for auto saving... */
+      setup_coding_system (Qemacs_mule, &coding);
+      /* ... but with the special flag to indicate to read in a
+        multibyte sequence for eight-bit-control char as is.  */
+      coding.flags = 1;
+      coding.src_multibyte = 0;
+      coding.dst_multibyte
+       = !NILP (current_buffer->enable_multibyte_characters);
+      coding.eol_type = CODING_EOL_LF;
+      coding_system_decided = 1;
+    }
+  else if (BEG < Z)
     {
       /* Decide the coding system to use for reading the file now
          because we can't use an optimized method for handling
@@ -3787,13 +3840,14 @@ actually used.  */)
                  buffer = Fget_buffer_create (build_string (" *code-converting-work*"));
                  buf = XBUFFER (buffer);
 
+                 delete_all_overlays (buf);
                  buf->directory = current_buffer->directory;
                  buf->read_only = Qnil;
                  buf->filename = Qnil;
                  buf->undo_list = Qt;
-                 buf->overlays_before = Qnil;
-                 buf->overlays_after = Qnil;
-                 
+                 eassert (buf->overlays_before == NULL);
+                 eassert (buf->overlays_after == NULL);
+
                  set_buffer_internal (buf);
                  Ferase_buffer ();
                  buf->enable_multibyte_characters = Qnil;
@@ -3803,7 +3857,7 @@ actually used.  */)
                  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--;
@@ -3968,11 +4022,11 @@ actually used.  */)
                break;
              total_read += nread;
            }
-         
+
          /* Scan this bufferful from the end, comparing with
             the Emacs buffer.  */
          bufpos = total_read;
-         
+
          /* Compare with same_at_start to avoid counting some buffer text
             as matching both at the file's beginning and at the end.  */
          while (bufpos > 0 && same_at_end > same_at_start
@@ -4229,7 +4283,7 @@ actually used.  */)
       if (coding.cmp_data && coding.cmp_data->used)
        coding_restore_composition (&coding, Fcurrent_buffer ());
       coding_free_composition_data (&coding);
-  
+
       /* Set `inserted' to the number of inserted characters.  */
       inserted = PT - temp;
 
@@ -4274,15 +4328,15 @@ actually used.  */)
      before exiting the loop, it is set to a negative value if I/O
      error occurs.  */
   how_much = 0;
-  
+
   /* Total bytes inserted.  */
   inserted = 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.  */
   {
     int gap_size = GAP_SIZE;
-    
+
     while (how_much < total)
       {
        /* try is reserved in some compilers (Microsoft C) */
@@ -4326,7 +4380,7 @@ actually used.  */)
            this = emacs_read (fd, BEG_ADDR + PT_BYTE - BEG_BYTE + inserted, trytry);
            immediate_quit = 0;
          }
-      
+
        if (this <= 0)
          {
            how_much = this;
@@ -4470,11 +4524,13 @@ actually used.  */)
                             inserted);
     }
 
+  /* Now INSERTED is measured in characters.  */
+
 #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 
+  if ((coding.eol_type == CODING_EOL_UNDECIDED
        || coding.eol_type == CODING_EOL_LF)
       && ! CODING_REQUIRE_DECODING (&coding))
     current_buffer->buffer_file_type = Qt;
@@ -4515,11 +4571,24 @@ actually used.  */)
                        Fcons (orig_filename, Qnil)));
     }
 
+  if (set_coding_system)
+    Vlast_coding_system_used = coding.symbol;
+
+  if (! NILP (Ffboundp (Qafter_insert_file_set_coding)))
+    {
+      insval = call1 (Qafter_insert_file_set_coding, make_number (inserted));
+      if (! NILP (insval))
+       {
+         CHECK_NUMBER (insval);
+         inserted = XFASTINT (insval);
+       }
+    }
+
   /* Decode file format */
   if (inserted > 0)
     {
       int empty_undo_list_p = 0;
-      
+
       /* If we're anyway going to discard undo information, don't
         record it in the first place.  The buffer's undo list at this
         point is either nil or t when visiting a file.  */
@@ -4528,19 +4597,16 @@ actually used.  */)
          empty_undo_list_p = NILP (current_buffer->undo_list);
          current_buffer->undo_list = Qt;
        }
-         
+
       insval = call3 (Qformat_decode,
                      Qnil, make_number (inserted), visit);
       CHECK_NUMBER (insval);
       inserted = XFASTINT (insval);
-      
+
       if (!NILP (visit))
        current_buffer->undo_list = empty_undo_list_p ? Qnil : Qt;
     }
 
-  if (set_coding_system)
-    Vlast_coding_system_used = coding.symbol;
-
   /* Call after-change hooks for the inserted text, aside from the case
      of normal visiting (not with REPLACE), which is done in a new buffer
      "before" the buffer is changed.  */
@@ -4619,9 +4685,24 @@ choose_write_coding_system (start, end, filename,
   Lisp_Object val;
 
   if (auto_saving)
-    val = Qnil;
+    {
+      /* We use emacs-mule for auto saving... */
+      setup_coding_system (Qemacs_mule, coding);
+      /* ... but with the special flag to indicate not to strip off
+        leading code of eight-bit-control chars.  */
+      coding->flags = 1;
+      goto done_setup_coding;
+    }
   else if (!NILP (Vcoding_system_for_write))
-    val = Vcoding_system_for_write;
+    {
+      val = Vcoding_system_for_write;
+      if (coding_system_require_warning
+         && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
+       /* Confirm that VAL can surely encode the current region.  */
+       val = call5 (Vselect_safe_coding_system_function,
+                    start, end, Fcons (Qt, Fcons (val, Qnil)),
+                    Qnil, filename);
+    }
   else
     {
       /* If the variable `buffer-file-coding-system' is set locally,
@@ -4644,7 +4725,7 @@ choose_write_coding_system (start, end, filename,
          if (NILP (current_buffer->enable_multibyte_characters))
            force_raw_text = 1;
        }
-       
+
       if (NILP (val))
        {
          /* Check file-coding-system-alist.  */
@@ -4666,7 +4747,7 @@ choose_write_coding_system (start, end, filename,
          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.  */
@@ -4813,11 +4894,14 @@ This does code conversion according to the value of
       return val;
     }
 
+  record_unwind_protect (save_restriction_restore, save_restriction_save ());
+
   /* Special kludge to simplify auto-saving.  */
   if (NILP (start))
     {
       XSETFASTINT (start, BEG);
       XSETFASTINT (end, Z);
+      Fwiden ();
     }
 
   record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
@@ -4960,7 +5044,7 @@ This does code conversion according to the value of
   if (!NILP (append) && !NILP (Ffile_regular_p (filename)))
     {
       long ret;
-      
+
       if (NUMBERP (append))
        ret = lseek (desc, XINT (append), 1);
       else
@@ -4974,7 +5058,7 @@ This does code conversion according to the value of
          report_file_error ("Lseek error", Fcons (filename, Qnil));
        }
     }
-  
+
   UNGCPRO;
 
 #ifdef VMS
@@ -5139,7 +5223,12 @@ This does code conversion according to the value of
     return Qnil;
 
   if (!auto_saving)
-    message_with_string ("Wrote %s", visit_file, 1);
+    message_with_string ((INTEGERP (append)
+                         ? "Updated %s"
+                         : ! NILP (append)
+                         ? "Added to %s"
+                         : "Wrote %s"),
+                        visit_file, 1);
 
   return Qnil;
 }
@@ -5170,7 +5259,7 @@ build_annotations (start, end)
   Lisp_Object p, res;
   struct gcpro gcpro1, gcpro2;
   Lisp_Object original_buffer;
-  int i;
+  int i, used_global = 0;
 
   XSETBUFFER (original_buffer, current_buffer);
 
@@ -5180,6 +5269,15 @@ build_annotations (start, end)
   while (CONSP (p))
     {
       struct buffer *given_buffer = current_buffer;
+      if (EQ (Qt, XCAR (p)) && !used_global)
+       { /* Use the global value of the hook.  */
+         Lisp_Object arg[2];
+         used_global = 1;
+         arg[0] = Fdefault_value (Qwrite_region_annotate_functions);
+         arg[1] = XCDR (p);
+         p = Fappend (2, arg);
+         continue;
+       }
       Vwrite_region_annotations_so_far = annotations;
       res = call2 (XCAR (p), start, end);
       /* If the function makes a different buffer current,
@@ -5206,7 +5304,7 @@ build_annotations (start, end)
   for (i = 0; CONSP (p); p = XCDR (p), ++i)
     {
       struct buffer *given_buffer = current_buffer;
-      
+
       Vwrite_region_annotations_so_far = annotations;
 
       /* Value is either a list of annotations or nil if the function
@@ -5220,7 +5318,7 @@ build_annotations (start, end)
          XSETFASTINT (end, ZV);
          annotations = Qnil;
        }
-      
+
       if (CONSP (res))
        annotations = merge (annotations, res, Qcar_less_than_car);
     }
@@ -5507,9 +5605,9 @@ auto_save_error (error)
   Lisp_Object args[3], msg;
   int i, nbytes;
   struct gcpro gcpro1;
-  
+
   ring_bell ();
-  
+
   args[0] = build_string ("Auto-saving %s: %s");
   args[1] = current_buffer->name;
   args[2] = Ferror_message_string (error);
@@ -5606,6 +5704,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
   int count = SPECPDL_INDEX ();
   int orig_minibuffer_auto_raise = minibuffer_auto_raise;
   int old_message_p = 0;
+  struct gcpro gcpro1, gcpro2;
 
   if (max_specpdl_size < specpdl_size + 40)
     max_specpdl_size = specpdl_size + 40;
@@ -5618,7 +5717,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
       old_message_p = push_message ();
       record_unwind_protect (pop_message_unwind, Qnil);
     }
-  
+
   /* 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;
@@ -5633,7 +5732,7 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
   if (STRINGP (Vauto_save_list_file_name))
     {
       Lisp_Object listfile;
-      
+
       listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
 
       /* Don't try to create the directory when shutting down Emacs,
@@ -5642,13 +5741,16 @@ A non-nil CURRENT-ONLY argument means save only current buffer.  */)
       if (!NILP (Vrun_hooks))
        {
          Lisp_Object dir;
+         dir = Qnil;
+         GCPRO2 (dir, listfile);
          dir = Ffile_name_directory (listfile);
          if (NILP (Ffile_directory_p (dir)))
            internal_condition_case_1 (do_auto_save_make_dir,
                                       dir, Fcons (Fcons (Qfile_error, Qnil), Qnil),
                                       do_auto_save_eh);
+         UNGCPRO;
        }
-      
+
       stream = fopen (SDATA (listfile), "w");
       if (stream != NULL)
        {
@@ -5944,7 +6046,7 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte
 #ifndef VMS
       if (EQ (Vread_file_name_predicate, Qfile_directory_p))
        {
-         /* Brute-force speed up for directory checking: 
+         /* Brute-force speed up for directory checking:
             Discard strings which don't end in a slash.  */
          for (comp = Qnil; CONSP (all); all = XCDR (all))
            {
@@ -5994,7 +6096,7 @@ Default name to DEFAULT-FILENAME if user enters a null string.
 Fourth arg MUSTMATCH non-nil means require existing file's name.
  Non-nil and non-t means also require confirmation after completion.
 Fifth arg INITIAL specifies text to start with.
-If optional sixth arg PREDICATE is non-nil, possible completions and the 
+If optional sixth arg PREDICATE is non-nil, possible completions and the
 resulting file name must satisfy (funcall PREDICATE NAME).
 DIR defaults to current buffer's directory default.
 
@@ -6007,6 +6109,7 @@ provides a file dialog box.  */)
   Lisp_Object val, insdef, tem;
   struct gcpro gcpro1, gcpro2;
   register char *homedir;
+  Lisp_Object decoded_homedir;
   int replace_in_history = 0;
   int add_to_history = 0;
   int count;
@@ -6029,25 +6132,29 @@ provides a file dialog box.  */)
       CORRECT_DIR_SEPS (homedir);
     }
 #endif
+  if (homedir != 0)
+    decoded_homedir
+      = DECODE_FILE (make_unibyte_string (homedir, strlen (homedir)));
   if (homedir != 0
       && STRINGP (dir)
-      && !strncmp (homedir, SDATA (dir), strlen (homedir))
-      && IS_DIRECTORY_SEP (SREF (dir, strlen (homedir))))
+      && !strncmp (SDATA (decoded_homedir), SDATA (dir),
+                  SBYTES (decoded_homedir))
+      && IS_DIRECTORY_SEP (SREF (dir, SBYTES (decoded_homedir))))
     {
-      dir = make_string (SDATA (dir) + strlen (homedir) - 1,
-                        SBYTES (dir) - strlen (homedir) + 1);
-      SSET (dir, 0, '~');
+      dir = Fsubstring (dir, make_number (SCHARS (decoded_homedir)), Qnil);
+      dir = concat2 (build_string ("~"), dir);
     }
   /* Likewise for default_filename.  */
   if (homedir != 0
       && STRINGP (default_filename)
-      && !strncmp (homedir, SDATA (default_filename), strlen (homedir))
-      && IS_DIRECTORY_SEP (SREF (default_filename, strlen (homedir))))
+      && !strncmp (SDATA (decoded_homedir), SDATA (default_filename),
+                  SBYTES (decoded_homedir))
+      && IS_DIRECTORY_SEP (SREF (default_filename, SBYTES (decoded_homedir))))
     {
       default_filename
-       = make_string (SDATA (default_filename) + strlen (homedir) - 1,
-                      SBYTES (default_filename) - strlen (homedir) + 1);
-      SSET (default_filename, 0, '~');
+       = Fsubstring (default_filename,
+                     make_number (SCHARS (decoded_homedir)), Qnil);
+      default_filename = concat2 (build_string ("~"), default_filename);
     }
   if (!NILP (default_filename))
     {
@@ -6097,12 +6204,12 @@ provides a file dialog box.  */)
 #endif
 
   specbind (intern ("minibuffer-completing-file-name"), Qt);
-  specbind (intern ("read-file-name-predicate"), 
+  specbind (intern ("read-file-name-predicate"),
            (NILP (predicate) ? Qfile_exists_p : predicate));
 
   GCPRO2 (insdef, default_filename);
-  
-#if defined (USE_MOTIF) || defined (HAVE_NTGUI)
+
+#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK)
   if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event))
       && use_dialog_box
       && have_menus_p ())
@@ -6177,7 +6284,7 @@ provides a file dialog box.  */)
        Fset (Qfile_name_history,
              Fcons (val1, tem));
     }
-    
+
   return val;
 }
 
@@ -6224,6 +6331,7 @@ syms_of_fileio ()
   Qwrite_region = intern ("write-region");
   Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
   Qset_visited_file_modtime = intern ("set-visited-file-modtime");
+  Qauto_save_coding = intern ("auto-save-coding");
 
   staticpro (&Qexpand_file_name);
   staticpro (&Qsubstitute_in_file_name);
@@ -6256,6 +6364,7 @@ syms_of_fileio ()
   staticpro (&Qwrite_region);
   staticpro (&Qverify_visited_file_modtime);
   staticpro (&Qset_visited_file_modtime);
+  staticpro (&Qauto_save_coding);
 
   Qfile_name_history = intern ("file-name-history");
   Fset (Qfile_name_history, Qnil);
@@ -6302,7 +6411,9 @@ same format as a regular save would use.  */);
   staticpro (&Qformat_decode);
   Qformat_annotate_function = intern ("format-annotate-function");
   staticpro (&Qformat_annotate_function);
-       
+  Qafter_insert_file_set_coding = intern ("after-insert-file-set-coding");
+  staticpro (&Qafter_insert_file_set_coding);
+
   Qcar_less_than_car = intern ("car-less-than-car");
   staticpro (&Qcar_less_than_car);
 
@@ -6342,10 +6453,7 @@ nil means use format `var'.  This variable is meaningful only on VMS.  */);
 
   DEFVAR_LISP ("directory-sep-char", &Vdirectory_sep_char,
               doc: /* Directory separator character for built-in functions that return file names.
-The value should be either ?/ or ?\\ (any other value is treated as ?\\).
-This variable affects the built-in functions only on Windows,
-on other platforms, it is initialized so that Lisp code can find out
-what the normal separator is.  */);
+The value is always ?/.  Don't use this variable, just use `/'.  */);
 
   DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
               doc: /* *Alist of elements (REGEXP . HANDLER) for file names handled specially.
@@ -6377,10 +6485,11 @@ or local variable spec of the tailing lines with `coding:' tag.  */);
 
   DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
               doc: /* A list of functions to be called at the end of `insert-file-contents'.
-Each is passed one argument, the number of bytes inserted.  It should return
-the new byte count, and leave point the same.  If `insert-file-contents' is
-intercepted by a handler from `file-name-handler-alist', that handler is
-responsible for calling the after-insert-file-functions if appropriate.  */);
+Each is passed one argument, the number of characters inserted.
+It should return the new character count, and leave point the same.
+If `insert-file-contents' is intercepted by a handler from
+`file-name-handler-alist', that handler is responsible for calling the
+functions in `after-insert-file-functions' if appropriate.  */);
   Vafter_insert_file_functions = Qnil;
 
   DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions,
@@ -6393,8 +6502,13 @@ inserted at the specified positions of the file being written (1 means to
 insert before the first byte written).  The POSITIONs must be sorted into
 increasing order.  If there are several functions in the list, the several
 lists are merged destructively.  Alternatively, the function can return
-with a different buffer current and value nil.*/);
+with a different buffer current; in that case it should pay attention
+to the annotations returned by previous functions and listed in
+`write-region-annotations-so-far'.*/);
   Vwrite_region_annotate_functions = Qnil;
+  staticpro (&Qwrite_region_annotate_functions);
+  Qwrite_region_annotate_functions
+    = intern ("write-region-annotate-functions");
 
   DEFVAR_LISP ("write-region-annotations-so-far",
               &Vwrite_region_annotations_so_far,
@@ -6478,3 +6592,5 @@ a non-nil value.  */);
 #endif
 }
 
+/* arch-tag: 64ba3fd7-f844-4fb2-ba4b-427eb928786c
+   (do not change this comment) */