(Fexpand_file_name) [DOS_NT]: Use the root directory
[bpt/emacs.git] / src / fileio.c
index 7621559..ad2d210 100644 (file)
@@ -23,7 +23,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 
-#if defined (USG5) || defined (BSD_SYSTEM) || defined (LINUX)
+#if defined (USG5) || defined (BSD_SYSTEM) || defined (GNU_LINUX)
 #include <fcntl.h>
 #endif
 
@@ -336,9 +336,11 @@ use the standard functions without calling themselves recursively.  */)
      Lisp_Object filename, operation;
 {
   /* This function must not munge the match data.  */
-  Lisp_Object chain, inhibited_handlers;
+  Lisp_Object chain, inhibited_handlers, result;
+  int pos = -1;
 
-  CHECK_STRING (filename, 0);
+  result = Qnil;
+  CHECK_STRING (filename);
 
   if (EQ (operation, Vinhibit_file_name_operation))
     inhibited_handlers = Vinhibit_file_name_handlers;
@@ -353,21 +355,26 @@ use the standard functions without calling themselves recursively.  */)
       if (CONSP (elt))
        {
          Lisp_Object string;
+         int match_pos;
          string = XCAR (elt);
-         if (STRINGP (string) && fast_string_match (string, filename) >= 0)
+         if (STRINGP (string)
+             && (match_pos = fast_string_match (string, filename)) > pos)
            {
              Lisp_Object handler, tem;
 
              handler = XCDR (elt);
              tem = Fmemq (handler, inhibited_handlers);
              if (NILP (tem))
-               return handler;
+               {
+                 result = handler;
+                 pos = match_pos;
+               }
            }
        }
 
       QUIT;
     }
-  return Qnil;
+  return result;
 }
 \f
 DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
@@ -384,7 +391,7 @@ on VMS, perhaps instead a string ending in `:', `]' or `>'.  */)
   register unsigned char *p;
   Lisp_Object handler;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -459,7 +466,7 @@ or the entire name if it contains no slash.  */)
   register unsigned char *beg, *p, *end;
   Lisp_Object handler;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -614,7 +621,7 @@ On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.  */)
   char *buf;
   Lisp_Object handler;
 
-  CHECK_STRING (file, 0);
+  CHECK_STRING (file);
   if (NILP (file))
     return Qnil;
 
@@ -805,7 +812,7 @@ it returns a file name such as \"[X]Y.DIR.1\".  */)
   char *buf;
   Lisp_Object handler;
 
-  CHECK_STRING (directory, 0);
+  CHECK_STRING (directory);
 
   if (NILP (directory))
     return Qnil;
@@ -870,7 +877,7 @@ make_temp_name (prefix, base64_p)
   char pidbuf[20];
   int pidlen;
      
-  CHECK_STRING (prefix, 0);
+  CHECK_STRING (prefix);
 
   /* VAL is created by adding 6 characters to PREFIX.  The first
      three are the PID of this process, in base 64, and the second
@@ -1019,7 +1026,7 @@ See also the function `substitute-in-file-name'.  */)
   int length;
   Lisp_Object handler;
 
-  CHECK_STRING (name, 0);
+  CHECK_STRING (name);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -1031,7 +1038,23 @@ See also the function `substitute-in-file-name'.  */)
   if (NILP (default_directory))
     default_directory = current_buffer->directory;
   if (! STRINGP (default_directory))
-    default_directory = build_string ("/");
+    {
+#ifdef DOS_NT
+      /* "/" is not considered a root directory on DOS_NT, so using "/"
+        here causes an infinite recursion in, e.g., the following:
+
+            (let (default-directory)
+             (expand-file-name "a"))
+
+        To avoid this, we set default_directory to the root of the
+        current drive.  */
+      extern char *emacs_root_dir (void);
+
+      default_directory = build_string (emacs_root_dir ());
+#else
+      default_directory = build_string ("/");
+#endif
+    }
 
   if (!NILP (default_directory))
     {
@@ -1648,6 +1671,16 @@ See also the function `substitute-in-file-name'.  */)
 }
 
 #if 0
+/* PLEASE DO NOT DELETE THIS COMMENTED-OUT VERSION!
+   This is the old version of expand-file-name, before it was thoroughly
+   rewritten for Emacs 10.31.  We leave this version here commented-out,
+   because the code is very complex and likely to have subtle bugs.  If
+   bugs _are_ found, it might be of interest to look at the old code and
+   see what did it do in the relevant situation.
+
+   Don't remove this code: it's true that it will be accessible via CVS,
+   but a few years from deletion, people will forget it is there.  */
+
 /* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.  */
 DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
   "Convert FILENAME to absolute, and canonicalize it.\n\
@@ -1676,7 +1709,7 @@ See also the function `substitute-in-file-name'.")
   int dots = 0;
 #endif /* VMS */
 
-  CHECK_STRING (name, 0);
+  CHECK_STRING (name);
 
 #ifdef VMS
   /* Filenames on VMS are always upper case.  */
@@ -1852,7 +1885,7 @@ See also the function `substitute-in-file-name'.")
     {
       if (NILP (defalt))
        defalt = current_buffer->directory;
-      CHECK_STRING (defalt, 1);
+      CHECK_STRING (defalt);
       newdir = XSTRING (defalt)->data;
     }
 
@@ -1994,7 +2027,7 @@ duplicates what `expand-file-name' does.  */)
   unsigned char *xnm;
   Lisp_Object handler;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -2091,9 +2124,13 @@ duplicates what `expand-file-name' does.  */)
 
        /* Get variable value */
        o = (unsigned char *) egetenv (target);
-       if (!o) goto badvar;
-       total += strlen (o);
-       substituted = 1;
+       if (o)
+         {
+           total += strlen (o);
+           substituted = 1;
+         }
+       else if (*p == '}')
+         goto badvar;
       }
 
   if (!substituted)
@@ -2143,9 +2180,11 @@ duplicates what `expand-file-name' does.  */)
        /* Get variable value */
        o = (unsigned char *) egetenv (target);
        if (!o)
-         goto badvar;
-
-       if (STRING_MULTIBYTE (filename))
+         {
+           *x++ = '$';
+           strcpy (x, target); x+= strlen (target);
+         }
+       else if (STRING_MULTIBYTE (filename))
          {
            /* If the original string is multibyte,
               convert what we substitute into multibyte.  */
@@ -2308,8 +2347,8 @@ A prefix arg makes KEEP-TIME non-nil.  */)
 
   encoded_file = encoded_newname = Qnil;
   GCPRO4 (file, newname, encoded_file, encoded_newname);
-  CHECK_STRING (file, 0);
-  CHECK_STRING (newname, 1);
+  CHECK_STRING (file);
+  CHECK_STRING (newname);
 
   if (!NILP (Ffile_directory_p (newname)))
     newname = Fexpand_file_name (file, newname);
@@ -2462,7 +2501,7 @@ DEFUN ("make-directory-internal", Fmake_directory_internal,
   Lisp_Object handler;
   Lisp_Object encoded_dir;
 
-  CHECK_STRING (directory, 0);
+  CHECK_STRING (directory);
   directory = Fexpand_file_name (directory, Qnil);
 
   handler = Ffind_file_name_handler (directory, Qmake_directory_internal);
@@ -2492,7 +2531,7 @@ DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete
   Lisp_Object handler;
   Lisp_Object encoded_dir;
 
-  CHECK_STRING (directory, 0);
+  CHECK_STRING (directory);
   directory = Fdirectory_file_name (Fexpand_file_name (directory, Qnil));
 
   handler = Ffind_file_name_handler (directory, Qdelete_directory);
@@ -2518,7 +2557,7 @@ If file has multiple names, it continues to exist with the other names.  */)
   Lisp_Object handler;
   Lisp_Object encoded_file;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   filename = Fexpand_file_name (filename, Qnil);
 
   handler = Ffind_file_name_handler (filename, Qdelete_file);
@@ -2569,8 +2608,8 @@ This is what happens in interactive use with M-x.  */)
 
   encoded_file = encoded_newname = Qnil;
   GCPRO4 (file, newname, encoded_file, encoded_newname);
-  CHECK_STRING (file, 0);
-  CHECK_STRING (newname, 1);
+  CHECK_STRING (file);
+  CHECK_STRING (newname);
   file = Fexpand_file_name (file, Qnil);
   newname = Fexpand_file_name (newname, Qnil);
 
@@ -2645,8 +2684,8 @@ This is what happens in interactive use with M-x.  */)
 
   GCPRO4 (file, newname, encoded_file, encoded_newname);
   encoded_file = encoded_newname = Qnil;
-  CHECK_STRING (file, 0);
-  CHECK_STRING (newname, 1);
+  CHECK_STRING (file);
+  CHECK_STRING (newname);
   file = Fexpand_file_name (file, Qnil);
   newname = Fexpand_file_name (newname, Qnil);
 
@@ -2708,8 +2747,8 @@ This happens for interactive use with M-x.  */)
 
   GCPRO4 (filename, linkname, encoded_filename, encoded_linkname);
   encoded_filename = encoded_linkname = Qnil;
-  CHECK_STRING (filename, 0);
-  CHECK_STRING (linkname, 1);
+  CHECK_STRING (filename);
+  CHECK_STRING (linkname);
   /* If the link target has a ~, we must expand it to get
      a truly valid file name.  Otherwise, do not expand;
      we want to permit links to relative file names.  */
@@ -2776,12 +2815,12 @@ If STRING is nil or a null string, the logical name NAME is deleted.  */)
      Lisp_Object name;
      Lisp_Object string;
 {
-  CHECK_STRING (name, 0);
+  CHECK_STRING (name);
   if (NILP (string))
     delete_logical_name (XSTRING (name)->data);
   else
     {
-      CHECK_STRING (string, 1);
+      CHECK_STRING (string);
 
       if (XSTRING (string)->size == 0)
        delete_logical_name (XSTRING (name)->data);
@@ -2802,8 +2841,8 @@ DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
 {
   int netresult;
 
-  CHECK_STRING (path, 0);
-  CHECK_STRING (login, 0);
+  CHECK_STRING (path);
+  CHECK_STRING (login);
 
   netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
 
@@ -2823,7 +2862,7 @@ On Unix, this is a name starting with a `/' or a `~'.  */)
 {
   unsigned char *ptr;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   ptr = XSTRING (filename)->data;
   if (IS_DIRECTORY_SEP (*ptr) || *ptr == '~'
 #ifdef VMS
@@ -2910,7 +2949,7 @@ See also `file-readable-p' and `file-attributes'.  */)
   Lisp_Object handler;
   struct stat statbuf;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   absname = Fexpand_file_name (filename, Qnil);
 
   /* If the file name has special constructs in it,
@@ -2933,7 +2972,7 @@ For a directory, this means you can access files in that directory.  */)
   Lisp_Object absname;
   Lisp_Object handler;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   absname = Fexpand_file_name (filename, Qnil);
 
   /* If the file name has special constructs in it,
@@ -2959,7 +2998,7 @@ See also `file-exists-p' and `file-attributes'.  */)
   int flags;
   struct stat statbuf;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   absname = Fexpand_file_name (filename, Qnil);
 
   /* If the file name has special constructs in it,
@@ -3007,7 +3046,7 @@ DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
   Lisp_Object handler;
   struct stat statbuf;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   absname = Fexpand_file_name (filename, Qnil);
 
   /* If the file name has special constructs in it,
@@ -3052,19 +3091,21 @@ If there is no error, we return nil.  */)
      (filename, string)
      Lisp_Object filename, string;
 {
-  Lisp_Object handler, encoded_filename;
+  Lisp_Object handler, encoded_filename, absname;
   int fd;
 
-  CHECK_STRING (filename, 0);
-  CHECK_STRING (string, 1);
+  CHECK_STRING (filename);
+  absname = Fexpand_file_name (filename, Qnil);
+
+  CHECK_STRING (string);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
-  handler = Ffind_file_name_handler (filename, Qaccess_file);
+  handler = Ffind_file_name_handler (absname, Qaccess_file);
   if (!NILP (handler))
-    return call3 (handler, Qaccess_file, filename, string);
+    return call3 (handler, Qaccess_file, absname, string);
 
-  encoded_filename = ENCODE_FILE (filename);
+  encoded_filename = ENCODE_FILE (absname);
 
   fd = emacs_open (XSTRING (encoded_filename)->data, O_RDONLY, 0);
   if (fd < 0)
@@ -3088,7 +3129,7 @@ Otherwise returns nil.  */)
   Lisp_Object val;
   Lisp_Object handler;
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   filename = Fexpand_file_name (filename, Qnil);
 
   /* If the file name has special constructs in it,
@@ -3163,8 +3204,9 @@ See `file-symlink-p' to distinguish symlinks.  */)
 }
 
 DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
-       doc: /* Return t if file FILENAME is the name of a directory as a file,
-and files in that directory can be opened by you.  In order to use a
+       doc: /* Return t if file FILENAME names a directory you can open.
+For the value to be t, FILENAME must specify the name of a directory as a file,
+and the directory must allow you to open files in it.  In order to use a
 directory as a buffer's current directory, this predicate must return true.
 A directory name spec may be given instead; then the value is t
 if the directory so specified exists and really is a readable and
@@ -3275,7 +3317,7 @@ Only the 12 low bits of MODE are used.  */)
   Lisp_Object handler;
 
   absname = Fexpand_file_name (filename, current_buffer->directory);
-  CHECK_NUMBER (mode, 1);
+  CHECK_NUMBER (mode);
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -3298,7 +3340,7 @@ This setting is inherited by subprocesses.  */)
      (mode)
      Lisp_Object mode;
 {
-  CHECK_NUMBER (mode, 0);
+  CHECK_NUMBER (mode);
 
   umask ((~ XINT (mode)) & 0777);
 
@@ -3349,8 +3391,8 @@ otherwise, if FILE2 does not exist, the answer is t.  */)
   Lisp_Object handler;
   struct gcpro gcpro1, gcpro2;
 
-  CHECK_STRING (file1, 0);
-  CHECK_STRING (file2, 0);
+  CHECK_STRING (file1);
+  CHECK_STRING (file2);
 
   absname1 = Qnil;
   GCPRO2 (absname1, file2);
@@ -3455,7 +3497,6 @@ read_non_regular ()
   nbytes = emacs_read (non_regular_fd,
                       BEG_ADDR + PT_BYTE - 1 + non_regular_inserted,
                       non_regular_nbytes);
-  Fsignal (Qquit, Qnil);
   immediate_quit = 0;
   return make_number (nbytes);
 }
@@ -3530,7 +3571,7 @@ actually used.  */)
 
   GCPRO4 (filename, val, p, orig_filename);
 
-  CHECK_STRING (filename, 0);
+  CHECK_STRING (filename);
   filename = Fexpand_file_name (filename, Qnil);
 
   /* If the file name has special constructs in it,
@@ -3624,12 +3665,12 @@ actually used.  */)
     }
 
   if (!NILP (beg))
-    CHECK_NUMBER (beg, 0);
+    CHECK_NUMBER (beg);
   else
     XSETFASTINT (beg, 0);
 
   if (!NILP (end))
-    CHECK_NUMBER (end, 0);
+    CHECK_NUMBER (end);
   else
     {
       if (! not_regular)
@@ -4446,7 +4487,7 @@ actually used.  */)
          
       insval = call3 (Qformat_decode,
                      Qnil, make_number (inserted), visit);
-      CHECK_NUMBER (insval, 0);
+      CHECK_NUMBER (insval);
       inserted = XFASTINT (insval);
       
       if (!NILP (visit))
@@ -4472,7 +4513,7 @@ actually used.  */)
       insval = call1 (Fcar (p), make_number (inserted));
       if (!NILP (insval))
        {
-         CHECK_NUMBER (insval, 0);
+         CHECK_NUMBER (insval);
          inserted = XFASTINT (insval);
        }
       QUIT;
@@ -4498,8 +4539,9 @@ actually used.  */)
   RETURN_UNGCPRO (unbind_to (count, val));
 }
 \f
-static Lisp_Object build_annotations P_ ((Lisp_Object, Lisp_Object,
-                                         Lisp_Object));
+static Lisp_Object build_annotations P_ ((Lisp_Object, Lisp_Object));
+static Lisp_Object build_annotations_2 P_ ((Lisp_Object, 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.
@@ -4522,11 +4564,113 @@ build_annotations_unwind (buf)
   return Qnil;
 }
 
+/* Decide the coding-system to encode the data with.  */
+
+void
+choose_write_coding_system (start, end, filename,
+                           append, visit, lockname, coding)
+     Lisp_Object start, end, filename, append, visit, lockname;
+     struct coding_system *coding;
+{
+  Lisp_Object val;
+
+  if (auto_saving)
+    val = Qnil;
+  else if (!NILP (Vcoding_system_for_write))
+    val = Vcoding_system_for_write;
+  else
+    {
+      /* 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 variable is explicitly 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.  */
+      int using_default_coding = 0;
+      int force_raw_text = 0;
+
+      val = current_buffer->buffer_file_coding_system;
+      if (NILP (val)
+         || NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil)))
+       {
+         val = Qnil;
+         if (NILP (current_buffer->enable_multibyte_characters))
+           force_raw_text = 1;
+       }
+       
+      if (NILP (val))
+       {
+         /* Check file-coding-system-alist.  */
+         Lisp_Object args[7], coding_systems;
+
+         args[0] = Qwrite_region; args[1] = start; args[2] = end;
+         args[3] = filename; args[4] = append; args[5] = visit;
+         args[6] = lockname;
+         coding_systems = Ffind_operation_coding_system (7, args);
+         if (CONSP (coding_systems) && !NILP (XCDR (coding_systems)))
+           val = XCDR (coding_systems);
+       }
+
+      if (NILP (val)
+         && !NILP (current_buffer->buffer_file_coding_system))
+       {
+         /* If we still have not decided a coding system, use the
+            default value of buffer-file-coding-system.  */
+         val = current_buffer->buffer_file_coding_system;
+         using_default_coding = 1;
+       }
+           
+      if (!force_raw_text
+         && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
+       /* Confirm that VAL can surely encode the current region.  */
+       val = call3 (Vselect_safe_coding_system_function, start, end, val);
+
+      setup_coding_system (Fcheck_coding_system (val), coding);
+      if (coding->eol_type == CODING_EOL_UNDECIDED
+         && !using_default_coding)
+       {
+         if (! EQ (default_buffer_file_coding.symbol,
+                   buffer_defaults.buffer_file_coding_system))
+           setup_coding_system (buffer_defaults.buffer_file_coding_system,
+                                &default_buffer_file_coding);
+         if (default_buffer_file_coding.eol_type != CODING_EOL_UNDECIDED)
+           {
+             Lisp_Object subsidiaries;
+
+             coding->eol_type = default_buffer_file_coding.eol_type;
+             subsidiaries = Fget (coding->symbol, Qeol_type);
+             if (VECTORP (subsidiaries)
+                 && XVECTOR (subsidiaries)->size == 3)
+               coding->symbol
+                 = XVECTOR (subsidiaries)->contents[coding->eol_type];
+           }
+       }
+
+      if (force_raw_text)
+       setup_raw_text_coding_system (coding);
+      goto done_setup_coding;
+    }
+
+  setup_coding_system (Fcheck_coding_system (val), coding);
+
+ done_setup_coding:
+  if (!STRINGP (start) && !NILP (current_buffer->selective_display))
+    coding->mode |= CODING_MODE_SELECTIVE_DISPLAY;
+}
+
 DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 7,
        "r\nFWrite region to file: \ni\ni\ni\np",
        doc: /* Write current region into specified file.
-When called from a program, takes three arguments:
-START, END and FILENAME.  START and END are buffer positions.
+When called from a program, requires three arguments:
+START, END and FILENAME.  START and END are normally buffer positions
+specifying the part of the buffer to write.
+If START is nil, that means to use the entire buffer contents.
+If START is a string, then output that string to the file
+instead of any buffer contents; END is ignored.
+
 Optional fourth argument APPEND if non-nil means
   append to existing file contents (if any).  If it is an integer,
   seek to that offset in the file before writing.
@@ -4546,8 +4690,6 @@ The optional seventh arg MUSTBENEW, if non-nil, insists on a check
   If MUSTBENEW is neither nil nor `excl', that means ask for
   confirmation before overwriting, but do go ahead and overwrite the file
   if the user confirms.
-Kludgy feature: if START is a string, then that string is written
-to the file, instead of any buffer contents, and END is ignored.
 
 This does code conversion according to the value of
 `coding-system-for-write', `buffer-file-coding-system', or
@@ -4586,118 +4728,22 @@ This does code conversion according to the value of
   if (!NILP (start) && !STRINGP (start))
     validate_region (&start, &end);
 
-  GCPRO4 (start, filename, visit, lockname);
-
-  /* Decide the coding-system to encode the data with.  */
-  {
-    Lisp_Object val;
-
-    if (auto_saving)
-      val = Qnil;
-    else if (!NILP (Vcoding_system_for_write))
-      val = Vcoding_system_for_write;
-    else
-      {
-       /* 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 variable is explicitly 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.  */
-       int using_default_coding = 0;
-       int force_raw_text = 0;
-
-       val = current_buffer->buffer_file_coding_system;
-       if (NILP (val)
-           || NILP (Flocal_variable_p (Qbuffer_file_coding_system, Qnil)))
-         {
-           val = Qnil;
-           if (NILP (current_buffer->enable_multibyte_characters))
-             force_raw_text = 1;
-         }
-       
-       if (NILP (val))
-         {
-           /* Check file-coding-system-alist.  */
-           Lisp_Object args[7], coding_systems;
-
-           args[0] = Qwrite_region; args[1] = start; args[2] = end;
-           args[3] = filename; args[4] = append; args[5] = visit;
-           args[6] = lockname;
-           coding_systems = Ffind_operation_coding_system (7, args);
-           if (CONSP (coding_systems) && !NILP (XCDR (coding_systems)))
-             val = XCDR (coding_systems);
-         }
-
-       if (NILP (val)
-           && !NILP (current_buffer->buffer_file_coding_system))
-         {
-           /* If we still have not decided a coding system, use the
-              default value of buffer-file-coding-system.  */
-           val = current_buffer->buffer_file_coding_system;
-           using_default_coding = 1;
-         }
-           
-       if (!force_raw_text
-           && !NILP (Ffboundp (Vselect_safe_coding_system_function)))
-         /* Confirm that VAL can surely encode the current region.  */
-         val = call3 (Vselect_safe_coding_system_function, start, end, val);
-
-       setup_coding_system (Fcheck_coding_system (val), &coding);
-       if (coding.eol_type == CODING_EOL_UNDECIDED
-           && !using_default_coding)
-         {
-           if (! EQ (default_buffer_file_coding.symbol,
-                     buffer_defaults.buffer_file_coding_system))
-             setup_coding_system (buffer_defaults.buffer_file_coding_system,
-                                  &default_buffer_file_coding);
-           if (default_buffer_file_coding.eol_type != CODING_EOL_UNDECIDED)
-             {
-               Lisp_Object subsidiaries;
-
-               coding.eol_type = default_buffer_file_coding.eol_type;
-               subsidiaries = Fget (coding.symbol, Qeol_type);
-               if (VECTORP (subsidiaries)
-                   && XVECTOR (subsidiaries)->size == 3)
-                 coding.symbol
-                   = XVECTOR (subsidiaries)->contents[coding.eol_type];
-             }
-         }
-
-       if (force_raw_text)
-         setup_raw_text_coding_system (&coding);
-       goto done_setup_coding;
-      }
-
-    setup_coding_system (Fcheck_coding_system (val), &coding);
-
-  done_setup_coding:
-    if (!STRINGP (start) && !NILP (current_buffer->selective_display))
-      coding.mode |= CODING_MODE_SELECTIVE_DISPLAY;
-  }
-
-  Vlast_coding_system_used = coding.symbol;
+  GCPRO5 (start, filename, visit, visit_file, lockname);
 
   filename = Fexpand_file_name (filename, Qnil);
 
-  if (! NILP (mustbenew) && !EQ (mustbenew, Qexcl))
+  if (!NILP (mustbenew) && !EQ (mustbenew, Qexcl))
     barf_or_query_if_file_exists (filename, "overwrite", 1, 0, 1);
 
   if (STRINGP (visit))
     visit_file = Fexpand_file_name (visit, Qnil);
   else
     visit_file = filename;
-  UNGCPRO;
-
-  annotations = Qnil;
 
   if (NILP (lockname))
     lockname = visit_file;
 
-  GCPRO5 (start, filename, annotations, visit_file, lockname);
+  annotations = Qnil;
 
   /* If the file name has special constructs in it,
      call the corresponding file handler.  */
@@ -4733,7 +4779,28 @@ This does code conversion according to the value of
   count1 = specpdl_ptr - specpdl;
 
   given_buffer = current_buffer;
-  annotations = build_annotations (start, end, coding.pre_write_conversion);
+  annotations = build_annotations (start, end);
+  if (current_buffer != given_buffer)
+    {
+      XSETFASTINT (start, BEGV);
+      XSETFASTINT (end, ZV);
+    }
+
+  UNGCPRO;
+
+  GCPRO5 (start, filename, annotations, visit_file, lockname);
+
+  /* Decide the coding-system to encode the data with.
+     We used to make this choice before calling build_annotations, but that
+     leads to problems when a write-annotate-function takes care of
+     unsavable chars (as was the case with X-Symbol).  */
+  choose_write_coding_system (start, end, filename,
+                             append, visit, lockname, &coding);
+  Vlast_coding_system_used = coding.symbol;
+
+  given_buffer = current_buffer;
+  annotations = build_annotations_2 (start, end,
+                                    coding.pre_write_conversion, annotations);
   if (current_buffer != given_buffer)
     {
       XSETFASTINT (start, BEGV);
@@ -5043,8 +5110,8 @@ DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
    as save-excursion would do.  */
 
 static Lisp_Object
-build_annotations (start, end, pre_write_conversion)
-     Lisp_Object start, end, pre_write_conversion;
+build_annotations (start, end)
+     Lisp_Object start, end;
 {
   Lisp_Object annotations;
   Lisp_Object p, res;
@@ -5105,6 +5172,18 @@ build_annotations (start, end, pre_write_conversion)
        annotations = merge (annotations, res, Qcar_less_than_car);
     }
 
+  UNGCPRO;
+  return annotations;
+}
+
+static Lisp_Object
+build_annotations_2 (start, end, pre_write_conversion, annotations)
+     Lisp_Object start, end, pre_write_conversion, annotations;
+{
+  struct gcpro gcpro1;
+  Lisp_Object res;
+
+  GCPRO1 (annotations);
   /* At last, do the same for the function PRE_WRITE_CONVERSION
      implied by the current coding-system.  */
   if (!NILP (pre_write_conversion))
@@ -5278,7 +5357,7 @@ This means that the file has not been changed since it was visited or saved.  */
   Lisp_Object handler;
   Lisp_Object filename;
 
-  CHECK_BUFFER (buf, 0);
+  CHECK_BUFFER (buf);
   b = XBUFFER (buf);
 
   if (!STRINGP (b->filename)) return Qt;
@@ -5711,7 +5790,7 @@ DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_inte
   int changed;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
 
-  CHECK_STRING (string, 0);
+  CHECK_STRING (string);
 
   realdir = dir;
   name = string;
@@ -5841,7 +5920,7 @@ provides a file dialog box.  */)
     }
   if (!NILP (default_filename))
     {
-      CHECK_STRING (default_filename, 3);
+      CHECK_STRING (default_filename);
       default_filename = double_dollars (default_filename);
     }
 
@@ -6050,17 +6129,17 @@ syms_of_fileio ()
 
   DEFVAR_LISP ("file-name-coding-system", &Vfile_name_coding_system,
               doc: /* *Coding system for encoding file names.
-If it is nil, default-file-name-coding-system (which see) is used.  */);
+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,
               doc: /* Default coding system for encoding file names.
-This variable is used only when file-name-coding-system is nil.
+This variable is used only when `file-name-coding-system' is nil.
 
-This variable is set/changed by the command set-language-environment.
+This variable is set/changed by the command `set-language-environment'.
 User should not set this variable manually,
-instead use file-name-coding-system to get a constant encoding
+instead use `file-name-coding-system' to get a constant encoding
 of file names regardless of the current language environment.  */);
   Vdefault_file_name_coding_system = Qnil;