Merge from emacs-23 branch, up to 2010-05-20T21:33:58Z!juri@jurta.org.
[bpt/emacs.git] / lisp / files.el
index 9a07509..312ecb3 100644 (file)
@@ -1,10 +1,11 @@
 ;;; files.el --- file input and output commands for Emacs
 
 ;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994, 1995, 1996,
-;;   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-;;   2007, 2008, 2009, 2010  Free Software Foundation, Inc.
+;;   1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;;   2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
+;; Package: emacs
 
 ;; This file is part of GNU Emacs.
 
@@ -56,7 +57,10 @@ when it has unsaved changes."
 A list of elements of the form (FROM . TO), each meaning to replace
 FROM with TO when it appears in a directory name.  This replacement is
 done when setting up the default directory of a newly visited file.
-*Every* FROM string should start with \"\\\\`\".
+
+FROM is matched against directory names anchored at the first
+character, so it should start with a \"\\\\`\", or, if directory
+names cannot have embedded newlines, with a \"^\".
 
 FROM and TO should be equivalent names, which refer to the
 same directory.  Do not use `~' in the TO strings;
@@ -66,9 +70,9 @@ Use this feature when you have directories which you normally refer to
 via absolute symbolic links.  Make TO the name of the link, and FROM
 the name it is linked to."
   :type '(repeat (cons :format "%v"
-                      :value ("" . "")
+                      :value ("\\`" . "")
                       (regexp :tag "From")
-                      (regexp :tag "To")))
+                      (string :tag "To")))
   :group 'abbrev
   :group 'find-file)
 
@@ -114,15 +118,17 @@ This variable is relevant only if `backup-by-copying' is nil."
   :type 'boolean
   :group 'backup)
 
-(defcustom backup-by-copying-when-mismatch nil
+(defcustom backup-by-copying-when-mismatch t
   "Non-nil means create backups by copying if this preserves owner or group.
 Renaming may still be used (subject to control of other variables)
 when it would not result in changing the owner or group of the file;
 that is, for files which are owned by you and whose group matches
 the default for a new file created there by you.
 This variable is relevant only if `backup-by-copying' is nil."
+  :version "24.1"
   :type 'boolean
   :group 'backup)
+(put 'backup-by-copying-when-mismatch 'permanent-local t)
 
 (defcustom backup-by-copying-when-privileged-mismatch 200
   "Non-nil means create backups by copying to preserve a privileged owner.
@@ -187,17 +193,6 @@ If the buffer is visiting a new file, the value is nil.")
   "Non-nil if visited file was read-only when visited.")
 (make-variable-buffer-local 'buffer-file-read-only)
 
-(defcustom temporary-file-directory
-  (file-name-as-directory
-   (cond ((memq system-type '(ms-dos windows-nt))
-         (or (getenv "TEMP") (getenv "TMPDIR") (getenv "TMP") "c:/temp"))
-        (t
-         (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "/tmp"))))
-  "The directory for writing temporary files."
-  :group 'files
-  :initialize 'custom-initialize-delay
-  :type 'directory)
-
 (defcustom small-temporary-file-directory
   (if (eq system-type 'ms-dos) (getenv "TMPDIR"))
   "The directory for writing small temporary files.
@@ -785,9 +780,10 @@ one or more of those symbols."
       ;; Switching from names to names+fullnames creates a non-monotonicity
       ;; which can cause problems with things like partial-completion.
       ;; To minimize the problem, filter out completion-regexp-list, so that
-      ;; M-x load-library RET t/x.e TAB finds some files.
-      (if completion-regexp-list
-          (setq names (all-completions "" names)))
+      ;; M-x load-library RET t/x.e TAB finds some files.  Also remove elements
+      ;; from `names' which only matched `string' when they still had
+      ;; their suffix.
+      (setq names (all-completions string names))
       ;; Remove duplicates of the first element, so that we can easily check
       ;; if `names' really only contains a single element.
       (when (cdr names) (setcdr names (delete (car names) (cdr names))))
@@ -933,6 +929,36 @@ to that remote system.
        (funcall handler 'file-remote-p file identification connected)
       nil)))
 
+(defcustom remote-file-name-inhibit-cache 10
+  "Whether to use the remote file-name cache for read access.
+
+When `nil', always use the cached values.
+When `t', never use them.
+A number means use them for that amount of seconds since they were
+cached.
+
+File attributes of remote files are cached for better performance.
+If they are changed out of Emacs' control, the cached values
+become invalid, and must be invalidated.
+
+In case a remote file is checked regularly, it might be
+reasonable to let-bind this variable to a value less then the
+time period between two checks.
+Example:
+
+  \(defun display-time-file-nonempty-p \(file)
+    \(let \(\(remote-file-name-inhibit-cache \(- display-time-interval 5)))
+      \(and \(file-exists-p file)
+           \(< 0 \(nth 7 \(file-attributes \(file-chase-links file)))))))"
+  :group 'files
+  :version "24.1"
+  :type `(choice
+         (const   :tag "Do not inhibit file name cache" nil)
+         (const   :tag "Do not use file name cache" t)
+         (integer :tag "Do not use file name cache"
+                  :format "Do not use file name cache older then %v seconds"
+                  :value 10)))
+
 (defun file-local-copy (file)
   "Copy the file FILE into a temporary file on this machine.
 Returns the name of the local copy, or nil, if FILE is directly
@@ -1532,8 +1558,8 @@ killed."
   (unless (run-hook-with-args-until-failure 'kill-buffer-query-functions)
     (error "Aborted"))
   (when (and (buffer-modified-p) buffer-file-name)
-    (if (yes-or-no-p (format "Buffer %s is modified; save it first? "
-                             (buffer-name)))
+    (if (yes-or-no-p "Buffer %s is modified; save it first? "
+                    (buffer-name))
         (save-buffer)
       (unless (yes-or-no-p "Kill and replace the buffer without saving it? ")
         (error "Aborted"))))
@@ -1735,12 +1761,11 @@ When nil, never request confirmation."
   "If file SIZE larger than `large-file-warning-threshold', allow user to abort.
 OP-TYPE specifies the file operation being performed (for message to user)."
   (when (and large-file-warning-threshold size
-          (> size large-file-warning-threshold)
-          (not (y-or-n-p
-                (format "File %s is large (%dMB), really %s? "
-                        (file-name-nondirectory filename)
-                        (/ size 1048576) op-type))))
-         (error "Aborted")))
+            (> size large-file-warning-threshold)
+            (not (y-or-n-p "File %s is large (%dMB), really %s? "
+                           (file-name-nondirectory filename)
+                           (/ size 1048576) op-type)))
+    (error "Aborted")))
 
 (defun find-file-noselect (filename &optional nowarn rawfile wildcards)
   "Read file FILENAME into a buffer and return the buffer.
@@ -2209,7 +2234,16 @@ since only a single case-insensitive search through the alist is made."
    (lambda (elt)
      (cons (purecopy (car elt)) (cdr elt)))
    `(;; do this first, so that .html.pl is Polish html, not Perl
-     ("\\.s?html?\\(\\.[a-zA-Z_]+\\)?\\'" . html-mode)
+     ("\\.[sx]?html?\\(\\.[a-zA-Z_]+\\)?\\'" . html-mode)
+     ("\\.svgz?\\'" . image-mode)
+     ("\\.svgz?\\'" . xml-mode)
+     ("\\.x[bp]m\\'" . image-mode)
+     ("\\.x[bp]m\\'" . c-mode)
+     ("\\.p[bpgn]m\\'" . image-mode)
+     ("\\.tiff?\\'" . image-mode)
+     ("\\.gif\\'" . image-mode)
+     ("\\.png\\'" . image-mode)
+     ("\\.jpe?g\\'" . image-mode)
      ("\\.te?xt\\'" . text-mode)
      ("\\.[tT]e[xX]\\'" . tex-mode)
      ("\\.ins\\'" . tex-mode)          ;Installation files for TeX packages.
@@ -2245,6 +2279,14 @@ since only a single case-insensitive search through the alist is made."
      ("\\.te?xi\\'" . texinfo-mode)
      ("\\.[sS]\\'" . asm-mode)
      ("\\.asm\\'" . asm-mode)
+     ("\\.css\\'" . css-mode)
+     ("\\.mixal\\'" . mixal-mode)
+     ("\\.gcov\\'" . compilation-mode)
+     ;; Besides .gdbinit, gdb documents other names to be usable for init
+     ;; files, cross-debuggers can use something like
+     ;; .PROCESSORNAME-gdbinit so that the host and target gdbinit files
+     ;; don't interfere with each other.
+     ("/\\.[a-z0-9-]*gdbinit" . gdb-script-mode)
      ("[cC]hange\\.?[lL]og?\\'" . change-log-mode)
      ("[cC]hange[lL]og[-.][0-9]+\\'" . change-log-mode)
      ("\\$CHANGE_LOG\\$\\.TXT" . change-log-mode)
@@ -2261,6 +2303,7 @@ since only a single case-insensitive search through the alist is made."
      ("\\.cl[so]\\'" . latex-mode)             ;LaTeX 2e class option
      ("\\.bbl\\'" . latex-mode)
      ("\\.bib\\'" . bibtex-mode)
+     ("\\.bst\\'" . bibtex-style-mode)
      ("\\.sql\\'" . sql-mode)
      ("\\.m[4c]\\'" . m4-mode)
      ("\\.mf\\'" . metafont-mode)
@@ -2296,6 +2339,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode)
      ("\\.oak\\'" . scheme-mode)
      ("\\.sgml?\\'" . sgml-mode)
      ("\\.x[ms]l\\'" . xml-mode)
+     ("\\.dbk\\'" . xml-mode)
      ("\\.dtd\\'" . sgml-mode)
      ("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
      ("\\.js\\'" . js-mode)            ; javascript-mode would be better
@@ -2309,6 +2353,20 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode)
      ("[:/]_emacs\\'" . emacs-lisp-mode)
      ("/crontab\\.X*[0-9]+\\'" . shell-script-mode)
      ("\\.ml\\'" . lisp-mode)
+     ;; Linux-2.6.9 uses some different suffix for linker scripts:
+     ;; "ld", "lds", "lds.S", "lds.in", "ld.script", and "ld.script.balo".
+     ;; eCos uses "ld" and "ldi".  Netbsd uses "ldscript.*".
+     ("\\.ld[si]?\\'" . ld-script-mode)
+     ("ld\\.?script\\'" . ld-script-mode)
+     ;; .xs is also used for ld scripts, but seems to be more commonly
+     ;; associated with Perl .xs files (C with Perl bindings).  (Bug#7071)
+     ("\\.xs\\'" . c-mode)
+     ;; Explained in binutils ld/genscripts.sh.  Eg:
+     ;; A .x script file is the default script.
+     ;; A .xr script is for linking without relocation (-r flag).  Etc.
+     ("\\.x[abdsru]?[cnw]?\\'" . ld-script-mode)
+     ("\\.zone\\'" . dns-mode)
+     ("\\.soa\\'" . dns-mode)
      ;; Common Lisp ASDF package system.
      ("\\.asd\\'" . lisp-mode)
      ("\\.\\(asn\\|mib\\|smi\\)\\'" . snmp-mode)
@@ -2316,7 +2374,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode)
      ("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
      ("\\.\\(dif\\|pat\\)\\'" . diff-mode) ; for MSDOG
      ("\\.[eE]?[pP][sS]\\'" . ps-mode)
-     ("\\.\\(?:PDF\\|DVI\\|pdf\\|dvi\\)\\'" . doc-view-mode)
+     ("\\.\\(?:PDF\\|DVI\\|OD[FGPST]\\|DOCX?\\|XLSX?\\|PPTX?\\|pdf\\|dvi\\|od[fgpst]\\|docx?\\|xlsx?\\|pptx?\\)\\'" . doc-view-mode-maybe)
      ("configure\\.\\(ac\\|in\\)\\'" . autoconf-mode)
      ("\\.s\\(v\\|iv\\|ieve\\)\\'" . sieve-mode)
      ("BROWSE\\'" . ebrowse-tree-mode)
@@ -2805,6 +2863,7 @@ asking you for confirmation."
        (no-update-autoloads     . booleanp)
        (tab-width               . integerp)   ;; C source code
        (truncate-lines          . booleanp)   ;; C source code
+       (word-wrap               . booleanp) ;; C source code
        (bidi-display-reordering . booleanp))) ;; C source code
 
 (put 'bidi-paragraph-direction 'safe-local-variable
@@ -2819,6 +2878,7 @@ is a file-local variable (a symbol) and VALUE is the value
 specified.  The actual value in the buffer may differ from VALUE,
 if it is changed by the major or minor modes, or by the user.")
 (make-variable-buffer-local 'file-local-variables-alist)
+(put 'file-local-variables-alist 'permanent-local t)
 
 (defvar dir-local-variables-alist nil
   "Alist of directory-local variable settings in the current buffer.
@@ -2848,91 +2908,80 @@ DIR-NAME is a directory name if these settings come from
 directory-local variables, or nil otherwise."
   (if noninteractive
       nil
-    (let ((name (or dir-name
-                   (if buffer-file-name
-                       (file-name-nondirectory buffer-file-name)
-                     (concat "buffer " (buffer-name)))))
-         (offer-save (and (eq enable-local-variables t) unsafe-vars))
-         prompt char)
-      (save-window-excursion
-       (let ((buf (get-buffer-create "*Local Variables*")))
-         (pop-to-buffer buf)
-         (set (make-local-variable 'cursor-type) nil)
-         (erase-buffer)
-         (if unsafe-vars
-             (insert "The local variables list in " name
-                     "\ncontains values that may not be safe (*)"
-                     (if risky-vars
-                         ", and variables that are risky (**)."
-                       "."))
-           (if risky-vars
-               (insert "The local variables list in " name
-                       "\ncontains variables that are risky (**).")
-             (insert "A local variables list is specified in " name ".")))
-         (insert "\n\nDo you want to apply it?  You can type
+    (save-window-excursion
+      (let* ((name (or dir-name
+                      (if buffer-file-name
+                          (file-name-nondirectory buffer-file-name)
+                        (concat "buffer " (buffer-name)))))
+            (offer-save (and (eq enable-local-variables t)
+                             unsafe-vars))
+            (exit-chars
+             (if offer-save '(?! ?y ?n ?\s ?\C-g) '(?y ?n ?\s ?\C-g)))
+            (buf (pop-to-buffer "*Local Variables*"))
+            prompt char)
+       (set (make-local-variable 'cursor-type) nil)
+       (erase-buffer)
+       (cond
+        (unsafe-vars
+         (insert "The local variables list in " name
+                 "\ncontains values that may not be safe (*)"
+                 (if risky-vars
+                     ", and variables that are risky (**)."
+                   ".")))
+        (risky-vars
+         (insert "The local variables list in " name
+                 "\ncontains variables that are risky (**)."))
+        (t
+         (insert "A local variables list is specified in " name ".")))
+       (insert "\n\nDo you want to apply it?  You can type
 y  -- to apply the local variables list.
 n  -- to ignore the local variables list.")
-         (if offer-save
-             (insert "
+       (if offer-save
+           (insert "
 !  -- to apply the local variables list, and permanently mark these
       values (*) as safe (in the future, they will be set automatically.)\n\n")
-           (insert "\n\n"))
-         (dolist (elt all-vars)
-           (cond ((member elt unsafe-vars)
-                  (insert "  * "))
-                 ((member elt risky-vars)
-                  (insert " ** "))
-                 (t
-                  (insert "    ")))
-           (princ (car elt) buf)
-           (insert " : ")
-            ;; Make strings with embedded whitespace easier to read.
-            (let ((print-escape-newlines t))
-              (prin1 (cdr elt) buf))
-           (insert "\n"))
-         (setq prompt
-               (format "Please type %s%s: "
-                       (if offer-save "y, n, or !" "y or n")
-                       (if (< (line-number-at-pos) (window-body-height))
-                           ""
-                         ", or C-v to scroll")))
-         (goto-char (point-min))
-         (let ((cursor-in-echo-area t)
-               (executing-kbd-macro executing-kbd-macro)
-               (exit-chars
-                (if offer-save '(?! ?y ?n ?\s ?\C-g) '(?y ?n ?\s ?\C-g)))
-               done)
-           (while (not done)
-             (message "%s" prompt)
-             (setq char (read-event))
-             (if (numberp char)
-                 (cond ((eq char ?\C-v)
-                        (condition-case nil
-                            (scroll-up)
-                          (error (goto-char (point-min)))))
-                       ;; read-event returns -1 if we are in a kbd
-                       ;; macro and there are no more events in the
-                       ;; macro.  In that case, attempt to get an
-                       ;; event interactively.
-                       ((and executing-kbd-macro (= char -1))
-                        (setq executing-kbd-macro nil))
-                       (t (setq done (memq (downcase char) exit-chars)))))))
-         (setq char (downcase char))
-         (when (and offer-save (= char ?!) unsafe-vars)
-           (dolist (elt unsafe-vars)
-             (add-to-list 'safe-local-variable-values elt))
-           ;; When this is called from desktop-restore-file-buffer,
-           ;; coding-system-for-read may be non-nil.  Reset it before
-           ;; writing to .emacs.
-           (if (or custom-file user-init-file)
-               (let ((coding-system-for-read nil))
-                 (customize-save-variable
-                  'safe-local-variable-values
-                  safe-local-variable-values))))
-         (kill-buffer buf)
-         (or (= char ?!)
-             (= char ?\s)
-             (= char ?y)))))))
+         (insert "\n\n"))
+       (dolist (elt all-vars)
+         (cond ((member elt unsafe-vars)
+                (insert "  * "))
+               ((member elt risky-vars)
+                (insert " ** "))
+               (t
+                (insert "    ")))
+         (princ (car elt) buf)
+         (insert " : ")
+         ;; Make strings with embedded whitespace easier to read.
+         (let ((print-escape-newlines t))
+           (prin1 (cdr elt) buf))
+         (insert "\n"))
+       (setq prompt
+             (format "Please type %s%s: "
+                     (if offer-save "y, n, or !" "y or n")
+                     (if (< (line-number-at-pos) (window-body-height))
+                         ""
+                       (push ?\C-v exit-chars)
+                       ", or C-v to scroll")))
+       (goto-char (point-min))
+       (while (null char)
+         (setq char (read-char-choice prompt exit-chars t))
+         (when (eq char ?\C-v)
+           (condition-case nil
+               (scroll-up)
+             (error (goto-char (point-min))))
+           (setq char nil)))
+       (kill-buffer buf)
+       (when (and offer-save (= char ?!) unsafe-vars)
+         (dolist (elt unsafe-vars)
+           (add-to-list 'safe-local-variable-values elt))
+         ;; When this is called from desktop-restore-file-buffer,
+         ;; coding-system-for-read may be non-nil.  Reset it before
+         ;; writing to .emacs.
+         (if (or custom-file user-init-file)
+             (let ((coding-system-for-read nil))
+               (customize-save-variable
+                'safe-local-variable-values
+                safe-local-variable-values))))
+       (memq char '(?! ?\s ?y))))))
 
 (defun hack-local-variables-prop-line (&optional mode-only)
   "Return local variables specified in the -*- line.
@@ -3169,7 +3218,10 @@ It is safe if any of these conditions are met:
    evaluates to a non-nil value with VAL as an argument."
   (or (member (cons sym val) safe-local-variable-values)
       (let ((safep (get sym 'safe-local-variable)))
-        (and (functionp safep) (funcall safep val)))))
+        (and (functionp safep)
+             ;; If the function signals an error, that means it
+             ;; can't assure us that the value is safe.
+             (with-demoted-errors (funcall safep val))))))
 
 (defun risky-local-variable-p (sym &optional ignored)
   "Non-nil if SYM could be dangerous as a file-local variable.
@@ -3311,22 +3363,29 @@ ROOT is the root directory of the project.
 Return the new variables list."
   (let* ((file-name (buffer-file-name))
         (sub-file-name (if file-name
+                            ;; FIXME: Why not use file-relative-name?
                            (substring file-name (length root)))))
-    (dolist (entry class-variables variables)
-      (let ((key (car entry)))
-       (cond
-        ((stringp key)
-         ;; Don't include this in the previous condition, because we
-         ;; want to filter all strings before the next condition.
-         (when (and sub-file-name
-                    (>= (length sub-file-name) (length key))
-                    (string= key (substring sub-file-name 0 (length key))))
-           (setq variables (dir-locals-collect-variables
-                            (cdr entry) root variables))))
-        ((or (not key)
-             (derived-mode-p key))
-         (setq variables (dir-locals-collect-mode-variables
-                          (cdr entry) variables))))))))
+    (condition-case err
+        (dolist (entry class-variables variables)
+          (let ((key (car entry)))
+            (cond
+             ((stringp key)
+              ;; Don't include this in the previous condition, because we
+              ;; want to filter all strings before the next condition.
+              (when (and sub-file-name
+                         (>= (length sub-file-name) (length key))
+                         (string-prefix-p key sub-file-name))
+                (setq variables (dir-locals-collect-variables
+                                 (cdr entry) root variables))))
+             ((or (not key)
+                  (derived-mode-p key))
+              (setq variables (dir-locals-collect-mode-variables
+                               (cdr entry) variables))))))
+      (error
+       ;; The file's content might be invalid (e.g. have a merge conflict), but
+       ;; that shouldn't prevent the user from opening the file.
+       (message ".dir-locals error: %s" (error-message-string err))
+       nil))))
 
 (defun dir-locals-set-directory-class (directory class &optional mtime)
   "Declare that the DIRECTORY root is an instance of CLASS.
@@ -3457,7 +3516,9 @@ and `file-local-variables-alist', without applying them."
          (dir-name nil))
       (cond
        ((stringp variables-file)
-       (setq dir-name (if (buffer-file-name) (file-name-directory (buffer-file-name)) default-directory))
+       (setq dir-name (if (buffer-file-name)
+                           (file-name-directory (buffer-file-name))
+                         default-directory))
        (setq class (dir-locals-read-from-file variables-file)))
        ((consp variables-file)
        (setq dir-name (nth 0 variables-file))
@@ -3523,8 +3584,8 @@ the old visited file has been renamed to the new name FILENAME."
     (let ((buffer (and filename (find-buffer-visiting filename))))
       (and buffer (not (eq buffer (current-buffer)))
           (not no-query)
-          (not (y-or-n-p (format "A buffer is visiting %s; proceed? "
-                                  filename)))
+          (not (y-or-n-p "A buffer is visiting %s; proceed? "
+                         filename))
           (error "Aborted")))
     (or (equal filename buffer-file-name)
        (progn
@@ -3635,7 +3696,7 @@ Interactively, confirmation is required unless you supply a prefix argument."
                                    (or buffer-file-name (buffer-name))))))
        (and confirm
             (file-exists-p filename)
-            (or (y-or-n-p (format "File `%s' exists; overwrite? " filename))
+            (or (y-or-n-p "File `%s' exists; overwrite? " filename)
                 (error "Canceled")))
        (set-visited-file-name filename (not confirm))))
   (set-buffer-modified-p t)
@@ -3689,8 +3750,8 @@ BACKUPNAME is the backup file name, which is the old file renamed."
                       (and targets
                            (or (eq delete-old-versions t) (eq delete-old-versions nil))
                            (or delete-old-versions
-                               (y-or-n-p (format "Delete excess backup versions of %s? "
-                                                 real-file-name)))))
+                               (y-or-n-p "Delete excess backup versions of %s? "
+                                         real-file-name))))
                      (modes (file-modes buffer-file-name))
                      (context (file-selinux-context buffer-file-name)))
                  ;; Actually write the back up file.
@@ -3717,10 +3778,9 @@ BACKUPNAME is the backup file name, which is the old file renamed."
                        (rename-file real-file-name backupname t)
                        (setq setmodes (list modes context backupname)))
                    (file-error
-                    ;; If trouble writing the backup, write it in ~.
-                    (setq backupname (expand-file-name
-                                      (convert-standard-filename
-                                       "~/%backup%~")))
+                    ;; If trouble writing the backup, write it in
+                    ;; .emacs.d/%backup%.
+                    (setq backupname (locate-user-emacs-file "%backup%~"))
                     (message "Cannot write backup file; backing up in %s"
                              backupname)
                     (sleep-for 1)
@@ -3767,21 +3827,25 @@ BACKUPNAME is the backup file name, which is the old file renamed."
   (and context
        (set-file-selinux-context to-name context)))
 
+(defvar file-name-version-regexp
+  "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+~\\)"
+  "Regular expression matching the backup/version part of a file name.
+Used by `file-name-sans-versions'.")
+
 (defun file-name-sans-versions (name &optional keep-backup-version)
   "Return file NAME sans backup versions or strings.
 This is a separate procedure so your site-init or startup file can
 redefine it.
 If the optional argument KEEP-BACKUP-VERSION is non-nil,
-we do not remove backup version numbers, only true file version numbers."
+we do not remove backup version numbers, only true file version numbers.
+See also `file-name-version-regexp'."
   (let ((handler (find-file-name-handler name 'file-name-sans-versions)))
     (if handler
        (funcall handler 'file-name-sans-versions name keep-backup-version)
       (substring name 0
-                (if keep-backup-version
-                    (length name)
-                  (or (string-match "\\.~[-[:alnum:]:#@^._]+~\\'" name)
-                      (string-match "~\\'" name)
-                      (length name)))))))
+                (unless keep-backup-version
+                   (string-match (concat file-name-version-regexp "\\'")
+                                 name))))))
 
 (defun file-ownership-preserved-p (file)
   "Return t if deleting FILE and rewriting it would preserve the owner."
@@ -4095,11 +4159,29 @@ on a DOS/Windows machine, it returns FILENAME in expanded form."
           (dremote (file-remote-p directory)))
       (if ;; Conditions for separate trees
          (or
-          ;; Test for different drives on DOS/Windows
+          ;; Test for different filesystems on DOS/Windows
           (and
            ;; Should `cygwin' really be included here?  --stef
            (memq system-type '(ms-dos cygwin windows-nt))
-           (not (eq t (compare-strings filename 0 2 directory 0 2))))
+           (or
+            ;; Test for different drive letters
+            (not (eq t (compare-strings filename 0 2 directory 0 2)))
+            ;; Test for UNCs on different servers
+            (not (eq t (compare-strings
+                        (progn
+                          (if (string-match "\\`//\\([^:/]+\\)/" filename)
+                              (match-string 1 filename)
+                            ;; Windows file names cannot have ? in
+                            ;; them, so use that to detect when
+                            ;; neither FILENAME nor DIRECTORY is a
+                            ;; UNC.
+                            "?"))
+                        0 nil
+                        (progn
+                          (if (string-match "\\`//\\([^:/]+\\)/" directory)
+                              (match-string 1 directory)
+                            "?"))
+                        0 nil t)))))
           ;; Test for different remote file system identification
           (not (equal fremote dremote)))
          filename
@@ -4242,8 +4324,8 @@ Before and after saving the buffer, this function runs
                        ;; Signal an error if the user specified the name of an
                        ;; existing directory.
                        (error "%s is a directory" filename)
-                     (unless (y-or-n-p (format "File `%s' exists; overwrite? "
-                                               filename))
+                     (unless (y-or-n-p "File `%s' exists; overwrite? "
+                                       filename)
                        (error "Canceled")))
                  ;; Signal an error if the specified name refers to a
                  ;; non-existing directory.
@@ -4256,8 +4338,8 @@ Before and after saving the buffer, this function runs
          (or (verify-visited-file-modtime (current-buffer))
              (not (file-exists-p buffer-file-name))
              (yes-or-no-p
-              (format "%s has changed since visited or saved.  Save anyway? "
-                      (file-name-nondirectory buffer-file-name)))
+              "%s has changed since visited or saved.  Save anyway? "
+              (file-name-nondirectory buffer-file-name))
              (error "Save not confirmed"))
          (save-restriction
            (widen)
@@ -4271,8 +4353,8 @@ Before and after saving the buffer, this function runs
                       (eq require-final-newline 'visit-save)
                       (and require-final-newline
                            (y-or-n-p
-                            (format "Buffer %s does not end in newline.  Add one? "
-                                    (buffer-name)))))
+                            "Buffer %s does not end in newline.  Add one? "
+                            (buffer-name))))
                   (save-excursion
                     (goto-char (point-max))
                     (insert ?\n))))
@@ -4334,9 +4416,9 @@ Before and after saving the buffer, this function runs
            (if (not (file-exists-p buffer-file-name))
                (error "Directory %s write-protected" dir)
              (if (yes-or-no-p
-                  (format "File %s is write-protected; try to save anyway? "
-                          (file-name-nondirectory
-                           buffer-file-name)))
+                  "File %s is write-protected; try to save anyway? "
+                  (file-name-nondirectory
+                   buffer-file-name))
                  (setq tempsetmodes t)
                (error "Attempt to save to a file which you aren't allowed to write"))))))
     (or buffer-backed-up
@@ -4428,28 +4510,8 @@ Before and after saving the buffer, this function runs
                   (setq buffer-backed-up nil))))))
     setmodes))
 
-(defun diff-buffer-with-file (&optional buffer)
-  "View the differences between BUFFER and its associated file.
-This requires the external program `diff' to be in your `exec-path'."
-  (interactive "bBuffer: ")
-  (with-current-buffer (get-buffer (or buffer (current-buffer)))
-    (if (and buffer-file-name
-            (file-exists-p buffer-file-name))
-       (let ((tempfile (make-temp-file "buffer-content-")))
-         (unwind-protect
-             (progn
-               (write-region nil nil tempfile nil 'nomessage)
-               (diff buffer-file-name tempfile nil t)
-               (sit-for 0))
-           (when (file-exists-p tempfile)
-             (delete-file tempfile))))
-      (message "Buffer %s has no associated file on disc" (buffer-name))
-      ;; Display that message for 1 second so that user can read it
-      ;; in the minibuffer.
-      (sit-for 1)))
-  ;; return always nil, so that save-buffers-kill-emacs will not move
-  ;; over to the next unsaved buffer when calling `d'.
-  nil)
+(declare-function diff-no-select "diff"
+                 (old new &optional switches no-async buf))
 
 (defvar save-some-buffers-action-alist
   `((?\C-r
@@ -4465,13 +4527,14 @@ This requires the external program `diff' to be in your `exec-path'."
     (?d ,(lambda (buf)
            (if (null (buffer-file-name buf))
                (message "Not applicable: no file")
-             (save-window-excursion (diff-buffer-with-file buf))
-             (if (not enable-recursive-minibuffers)
-                 (progn (display-buffer (get-buffer-create "*Diff*"))
-                        (setq other-window-scroll-buffer "*Diff*"))
-               (view-buffer (get-buffer-create "*Diff*")
-                            (lambda (_) (exit-recursive-edit)))
-               (recursive-edit)))
+             (require 'diff)            ;for diff-no-select.
+             (let ((diffbuf (diff-no-select (buffer-file-name buf) buf
+                                            nil 'noasync)))
+               (if (not enable-recursive-minibuffers)
+                   (progn (display-buffer diffbuf)
+                          (setq other-window-scroll-buffer diffbuf))
+                 (view-buffer diffbuf (lambda (_) (exit-recursive-edit)))
+                 (recursive-edit))))
            ;; Return nil to ask about BUF again.
            nil)
        ,(purecopy "view changes in this buffer")))
@@ -4546,8 +4609,7 @@ change the additional actions you can take on files."
           (progn
             (if (or arg
                     (eq save-abbrevs 'silently)
-                    (y-or-n-p (format "Save abbrevs in %s? "
-                                      abbrev-file-name)))
+                    (y-or-n-p "Save abbrevs in %s? " abbrev-file-name))
                 (write-abbrev-file nil))
             ;; Don't keep bothering user if he says no.
             (setq abbrevs-changed nil)
@@ -4722,8 +4784,8 @@ given.  With a prefix argument, TRASH is nil."
      (list dir
           (if (directory-files dir nil directory-files-no-dot-files-regexp)
               (y-or-n-p
-               (format "Directory `%s' is not empty, really %s? "
-                       dir (if trashing "trash" "delete")))
+               "Directory `%s' is not empty, really %s? "
+               dir (if trashing "trash" "delete"))
             nil)
           (null current-prefix-arg))))
   ;; If default-directory is a remote directory, make sure we find its
@@ -4922,8 +4984,8 @@ non-nil, it is called instead of rereading visited file contents."
                          (dolist (regexp revert-without-query)
                            (when (string-match regexp file-name)
                              (throw 'found t)))))
-                  (yes-or-no-p (format "Revert buffer from file %s? "
-                                       file-name)))
+                  (yes-or-no-p "Revert buffer from file %s? "
+                               file-name))
               (run-hooks 'before-revert-hook)
               ;; If file was backed up but has changed since,
               ;; we should make another backup.
@@ -5043,7 +5105,7 @@ non-nil, it is called instead of rereading visited file contents."
                   ;; to emulate what `ls' did in that case.
                   (insert-directory-safely file switches)
                   (insert-directory-safely file-name switches))))
-            (yes-or-no-p (format "Recover auto save file %s? " file-name)))
+            (yes-or-no-p "Recover auto save file %s? " file-name))
           (switch-to-buffer (find-file-noselect file t))
           (let ((inhibit-read-only t)
                 ;; Keep the current buffer-file-coding-system.
@@ -5164,9 +5226,9 @@ This command is used in the special Dired buffer created by
 (defun kill-buffer-ask (buffer)
   "Kill BUFFER if confirmed."
   (when (yes-or-no-p
-         (format "Buffer %s %s.  Kill? " (buffer-name buffer)
-                 (if (buffer-modified-p buffer)
-                     "HAS BEEN EDITED" "is unmodified")))
+        "Buffer %s %s.  Kill? " (buffer-name buffer)
+        (if (buffer-modified-p buffer)
+            "HAS BEEN EDITED" "is unmodified"))
     (kill-buffer buffer)))
 
 (defun kill-some-buffers (&optional list)
@@ -5561,12 +5623,14 @@ preference to the program given by this variable."
 
 (defun get-free-disk-space (dir)
   "Return the amount of free space on directory DIR's file system.
-The result is a string that gives the number of free 1KB blocks,
-or nil if the system call or the program which retrieve the information
-fail.  It returns also nil when DIR is a remote directory.
-
-This function calls `file-system-info' if it is available, or invokes the
-program specified by `directory-free-space-program' if that is non-nil."
+The return value is a string describing the amount of free
+space (normally, the number of free 1KB blocks).
+
+This function calls `file-system-info' if it is available, or
+invokes the program specified by `directory-free-space-program'
+and `directory-free-space-args'.  If the system call or program
+is unsuccessful, or if DIR is a remote directory, this function
+returns nil."
   (unless (file-remote-p dir)
     ;; Try to find the number of free blocks.  Non-Posix systems don't
     ;; always have df, but might have an equivalent system call.
@@ -5586,19 +5650,17 @@ program specified by `directory-free-space-program' if that is non-nil."
                                         directory-free-space-args
                                         dir)
                           0)))
-           ;; Usual format is a header line followed by a line of
-           ;; numbers.
+           ;; Assume that the "available" column is before the
+           ;; "capacity" column.  Find the "%" and scan backward.
            (goto-char (point-min))
            (forward-line 1)
-           (if (not (eobp))
-               (progn
-                 ;; Move to the end of the "available blocks" number.
-                 (skip-chars-forward "^ \t")
-                 (forward-word 3)
-                 ;; Copy it into AVAILABLE.
-                 (let ((end (point)))
-                   (forward-word -1)
-                   (buffer-substring (point) end))))))))))
+           (when (re-search-forward
+                  "[[:space:]]+[^[:space:]]+%[^%]*$"
+                  (line-end-position) t)
+             (goto-char (match-beginning 0))
+             (let ((endpt (point)))
+               (skip-chars-backward "^[:space:]")
+               (buffer-substring-no-properties (point) endpt)))))))))
 
 ;; The following expression replaces `dired-move-to-filename-regexp'.
 (defvar directory-listing-before-filename-regexp
@@ -6390,5 +6452,4 @@ Otherwise, trash FILENAME using the freedesktop.org conventions,
 (define-key ctl-x-5-map "r" 'find-file-read-only-other-frame)
 (define-key ctl-x-5-map "\C-o" 'display-buffer-other-frame)
 
-;; arch-tag: bc68d3ea-19ca-468b-aac6-3a4a7766101f
 ;;; files.el ends here