]> code.delx.au - gnu-emacs/blobdiff - lisp/files.el
Update docs for `customize-mode'
[gnu-emacs] / lisp / files.el
index 0fdf0048ac45553082cf8051d8813f2bbfb4d3c6..1f97fa5f52fba3a67c5c654c620f87e6282362f3 100644 (file)
@@ -1,6 +1,6 @@
 ;;; files.el --- file input and output commands for Emacs  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1985-1987, 1992-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1985-1987, 1992-2016 Free Software Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
 ;; Package: emacs
@@ -55,7 +55,7 @@ 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.
 
 FROM is matched against directory names anchored at the first
-character, so it should start with a \"\\\\`\", or, if directory
+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
@@ -573,6 +573,12 @@ using \\[read-only-mode]."
 
 Maximum length of the history list is determined by the value
 of `history-length', which see.")
+
+(defvar save-silently nil
+  "If non-nil, avoid messages when saving files.
+Error-related messages will still be printed, but all other
+messages will not.")
+
 \f
 (put 'ange-ftp-completion-hook-function 'safe-magic t)
 (defun ange-ftp-completion-hook-function (op &rest args)
@@ -648,10 +654,14 @@ the value of `default-directory'."
                  'file-directory-p))
 
 \f
-(defun pwd ()
-  "Show the current default directory."
-  (interactive nil)
-  (message "Directory %s" default-directory))
+(defun pwd (&optional insert)
+  "Show the current default directory.
+With prefix argument INSERT, insert the current default directory
+at point instead."
+  (interactive "P")
+  (if insert
+      (insert default-directory)
+    (message "Directory %s" default-directory)))
 
 (defvar cd-path nil
   "Value of the CDPATH environment variable, as a list.
@@ -730,20 +740,27 @@ The path separator is colon in GNU and GNU-like systems."
        (error "No such directory found via CDPATH environment variable"))))
 
 (defsubst directory-name-p (name)
-  "Return non-nil if NAME ends with a slash character."
-  (and (> (length name) 0)
-       (char-equal (aref name (1- (length name))) ?/)))
-
-(defun directory-files-recursively (dir match &optional include-directories)
-  "Return all files under DIR that have file names matching MATCH (a regexp).
+  "Return non-nil if NAME ends with a directory separator character."
+  (let ((len (length name))
+        (lastc ?.))
+    (if (> len 0)
+        (setq lastc (aref name (1- len))))
+    (or (= lastc ?/)
+        (and (memq system-type '(windows-nt ms-dos))
+             (= lastc ?\\)))))
+
+(defun directory-files-recursively (dir regexp &optional include-directories)
+  "Return list of all files under DIR that have file names matching REGEXP.
 This function works recursively.  Files are returned in \"depth first\"
-and alphabetical order.
-If INCLUDE-DIRECTORIES, also include directories that have matching names."
+order, and files from each directory are sorted in alphabetical order.
+Each file name appears in the returned list in its absolute form.
+Optional argument INCLUDE-DIRECTORIES non-nil means also include in the
+output directories whose names match REGEXP."
   (let ((result nil)
        (files nil)
        ;; When DIR is "/", remote file names like "/method:" could
        ;; also be offered.  We shall suppress them.
-       (tramp-mode (and tramp-mode (file-remote-p dir))))
+       (tramp-mode (and tramp-mode (file-remote-p (expand-file-name dir)))))
     (dolist (file (sort (file-name-all-completions "" dir)
                        'string<))
       (unless (member file '("./" "../"))
@@ -754,19 +771,23 @@ If INCLUDE-DIRECTORIES, also include directories that have matching names."
              (unless (file-symlink-p full-file)
                (setq result
                      (nconc result (directory-files-recursively
-                                    full-file match include-directories))))
+                                    full-file regexp include-directories))))
              (when (and include-directories
-                        (string-match match leaf))
+                        (string-match regexp leaf))
                (setq result (nconc result (list full-file)))))
-         (when (string-match match file)
+         (when (string-match regexp file)
            (push (expand-file-name file dir) files)))))
     (nconc result (nreverse files))))
 
+(defvar module-file-suffix)
+
 (defun load-file (file)
   "Load the Lisp file named FILE."
-  ;; This is a case where .elc makes a lot of sense.
+  ;; This is a case where .elc and .so/.dll make a lot of sense.
   (interactive (list (let ((completion-ignored-extensions
-                           (remove ".elc" completion-ignored-extensions)))
+                            (remove module-file-suffix
+                                    (remove ".elc"
+                                            completion-ignored-extensions))))
                       (read-file-name "Load file: " nil nil 'lambda))))
   (load (expand-file-name file) nil nil t))
 
@@ -777,8 +798,8 @@ return nil.
 PATH should be a list of directories to look in, like the lists in
 `exec-path' or `load-path'.
 If SUFFIXES is non-nil, it should be a list of suffixes to append to
-file name when searching.  If SUFFIXES is nil, it is equivalent to '(\"\").
-Use '(\"/\") to disable PATH search, but still try the suffixes in SUFFIXES.
+file name when searching.  If SUFFIXES is nil, it is equivalent to (\"\").
+Use (\"/\") to disable PATH search, but still try the suffixes in SUFFIXES.
 If non-nil, PREDICATE is used instead of `file-readable-p'.
 
 This function will normally skip directories, so if you want it to find
@@ -1002,6 +1023,7 @@ Return nil if COMMAND is not found anywhere in `exec-path'."
 
 (defun load-library (library)
   "Load the Emacs Lisp library named LIBRARY.
+LIBRARY should be a string.
 This is an interface to the function `load'.  LIBRARY is searched
 for in `load-path', both with and without `load-suffixes' (as
 well as `load-file-rep-suffixes').
@@ -1009,10 +1031,11 @@ well as `load-file-rep-suffixes').
 See Info node `(emacs)Lisp Libraries' for more details.
 See `load-file' for a different interface to `load'."
   (interactive
-   (list (completing-read "Load library: "
-                         (apply-partially 'locate-file-completion-table
-                                           load-path
-                                           (get-load-suffixes)))))
+   (let (completion-ignored-extensions)
+     (list (completing-read "Load library: "
+                            (apply-partially 'locate-file-completion-table
+                                             load-path
+                                             (get-load-suffixes))))))
   (load library))
 
 (defun file-remote-p (file &optional identification connected)
@@ -1047,7 +1070,7 @@ Tip: You can use this expansion of remote identifier components
      to derive a new remote file name from an existing one.  For
      example, if FILE is \"/sudo::/path/to/file\" then
 
-       \(concat \(file-remote-p FILE) \"/bin/sh\")
+       (concat (file-remote-p FILE) \"/bin/sh\")
 
      returns a remote file name for file \"/bin/sh\" that has the
      same remote identifier as FILE but expanded; a name such as
@@ -1082,14 +1105,14 @@ Tip: You can use this expansion of remote identifier components
 
 (defcustom remote-file-name-inhibit-cache 10
   "Whether to use the remote file-name cache for read access.
-When `nil', never expire cached values (caution)
-When `t', never use the cache (safe, but may be slow)
+When nil, never expire cached values (caution)
+When t, never use the cache (safe, but may be slow)
 A number means use cached values for that amount of seconds since caching.
 
 The attributes of remote files are cached for better performance.
 If they are changed outside of Emacs's control, the cached values
 become invalid, and must be reread.  If you are sure that nothing
-other than Emacs changes the files, you can set this variable to `nil'.
+other than Emacs changes the files, you can set this variable to nil.
 
 If a remote file is checked regularly, it might be a good idea to
 let-bind this variable to a value less than the interval between
@@ -1408,8 +1431,10 @@ return value, which may be passed as the REQUIRE-MATCH arg to
 
 (defmacro minibuffer-with-setup-hook (fun &rest body)
   "Temporarily add FUN to `minibuffer-setup-hook' while executing BODY.
-FUN can also be (:append FUN1), in which case FUN1 is appended to
-`minibuffer-setup-hook'.
+
+By default, FUN is prepended to `minibuffer-setup-hook'.  But if FUN is of
+the form `(:append FUN1)', FUN1 will be appended to `minibuffer-setup-hook'
+instead of prepending it.
 
 BODY should use the minibuffer at most once.
 Recursive uses of the minibuffer are unaffected (FUN is not
@@ -1630,7 +1655,9 @@ killed."
   (unless (run-hook-with-args-until-failure 'kill-buffer-query-functions)
     (user-error "Aborted"))
   (and (buffer-modified-p) buffer-file-name
-       (not (yes-or-no-p "Kill and replace the buffer without saving it? "))
+       (not (yes-or-no-p
+             (format-message "Kill and replace buffer `%s' without saving it? "
+                             (buffer-name))))
        (user-error "Aborted"))
   (let ((obuf (current-buffer))
        (ofile buffer-file-name)
@@ -1865,6 +1892,13 @@ If that fails, try to open it with `find-file-literally'
             out-of-memory-warning-percentage
             (file-size-human-readable (* total-free-memory 1024)))))))))
 
+(defun files--message (format &rest args)
+  "Like `message', except sometimes don't print to minibuffer.
+If the variable `save-silently' is non-nil, the message is not
+displayed on the minibuffer."
+  (apply #'message format args)
+  (when save-silently (message nil)))
+
 (defun find-file-noselect (filename &optional nowarn rawfile wildcards)
   "Read file FILENAME into a buffer and return the buffer.
 If a buffer exists visiting FILENAME, return that one, but
@@ -1910,8 +1944,8 @@ the various files."
              (or nowarn
                  find-file-suppress-same-file-warnings
                  (string-equal filename (buffer-file-name other))
-                 (message "%s and %s are the same file"
-                          filename (buffer-file-name other)))
+                 (files--message "%s and %s are the same file"
+                                  filename (buffer-file-name other)))
              ;; Optionally also find that buffer.
              (if (or find-file-existing-other-name find-file-visit-truename)
                  (setq buf other))))
@@ -2109,6 +2143,7 @@ Do you want to revisit the file normally now? ")
 \f
 (defun insert-file-contents-literally (filename &optional visit beg end replace)
   "Like `insert-file-contents', but only reads in the file literally.
+See `insert-file-contents' for an explanation of the parameters.
 A buffer may be modified in several ways after reading into the buffer,
 due to Emacs features such as format decoding, character code
 conversion, `find-file-hook', automatic uncompression, etc.
@@ -2264,18 +2299,7 @@ unless NOMODES is non-nil."
       (view-mode-enter))
     (run-hooks 'find-file-hook)))
 
-(defmacro report-errors (format &rest body)
-  "Eval BODY and turn any error into a FORMAT message.
-FORMAT can have a %s escape which will be replaced with the actual error.
-If `debug-on-error' is set, errors are not caught, so that you can
-debug them.
-Avoid using a large BODY since it is duplicated."
-  (declare (debug t) (indent 1))
-  `(if debug-on-error
-       (progn . ,body)
-     (condition-case err
-        (progn . ,body)
-       (error (message ,format (prin1-to-string err))))))
+(define-obsolete-function-alias 'report-errors 'with-demoted-errors "25.1")
 
 (defun normal-mode (&optional find-file)
   "Choose the major mode for this buffer automatically.
@@ -2296,9 +2320,9 @@ in that case, this function acts as if `enable-local-variables' were t."
   (let ((enable-local-variables (or (not find-file) enable-local-variables)))
     ;; FIXME this is less efficient than it could be, since both
     ;; s-a-m and h-l-v may parse the same regions, looking for "mode:".
-    (report-errors "File mode specification error: %s"
+    (with-demoted-errors "File mode specification error: %s"
       (set-auto-mode))
-    (report-errors "File local-variables error: %s"
+    (with-demoted-errors "File local-variables error: %s"
       (hack-local-variables)))
   ;; Turn font lock off and on, to make sure it takes account of
   ;; whatever file local variables are relevant to it.
@@ -2506,7 +2530,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode)
      ;; this has lower priority to avoid matching changelog.sgml etc.
      ("[cC]hange[lL]og[-.][-0-9a-z]+\\'" . change-log-mode)
      ;; either user's dot-files or under /etc or some such
-     ("/\\.?\\(?:gnokiirc\\|kde.*rc\\|mime\\.types\\|wgetrc\\)\\'" . conf-mode)
+     ("/\\.?\\(?:gitconfig\\|gnokiirc\\|hgrc\\|kde.*rc\\|mime\\.types\\|wgetrc\\)\\'" . conf-mode)
      ;; alas not all ~/.*rc files are like this
      ("/\\.\\(?:enigma\\|gltron\\|gtk\\|hxplayer\\|net\\|neverball\\|qt/.+\\|realplayer\\|scummvm\\|sversion\\|sylpheed/.+\\|xmp\\)rc\\'" . conf-mode)
      ("/\\.\\(?:gdbtkinit\\|grip\\|orbital/.+txt\\|rhosts\\|tuxracer/options\\)\\'" . conf-mode)
@@ -2593,7 +2617,7 @@ and `magic-mode-alist', which determines modes based on file contents.")
   "Alist mapping interpreter names to major modes.
 This is used for files whose first lines match `auto-mode-interpreter-regexp'.
 Each element looks like (REGEXP . MODE).
-If \\\\`REGEXP\\\\' matches the name (minus any directory part) of
+If REGEXP matches the entire name (minus any directory part) of
 the interpreter specified in the first line of a script, enable
 major mode MODE.
 
@@ -3297,7 +3321,7 @@ local variables, but directory-local variables may still be applied."
        result)
     (unless mode-only
       (setq file-local-variables-alist nil)
-      (report-errors "Directory-local variables error: %s"
+      (with-demoted-errors "Directory-local variables error: %s"
        ;; Note this is a no-op if enable-local-variables is nil.
        (hack-dir-local-variables)))
     ;; This entire function is basically a no-op if enable-local-variables
@@ -3362,7 +3386,7 @@ local variables, but directory-local variables may still be applied."
                      (error "Local variables entry is missing the prefix"))
                    (end-of-line)
                    ;; Discard the suffix.
-                   (if (looking-back suffix)
+                   (if (looking-back suffix (line-beginning-position))
                        (delete-region (match-beginning 0) (point))
                      (error "Local variables entry is missing the suffix"))
                    (forward-line 1))
@@ -3399,10 +3423,15 @@ local variables, but directory-local variables may still be applied."
                               (unless hack-local-variables--warned-lexical
                                 (setq hack-local-variables--warned-lexical t)
                                 (display-warning
-                                  :warning
-                                  (format "%s: `lexical-binding' at end of file unreliable"
-                                          (file-name-nondirectory
-                                           (or buffer-file-name ""))))))
+                                  'files
+                                  (format-message
+                                   "%s: `lexical-binding' at end of file unreliable"
+                                   (file-name-nondirectory
+                                    ;; We are called from
+                                    ;; 'with-temp-buffer', so we need
+                                    ;; to use 'thisbuf's name in the
+                                    ;; warning message.
+                                    (or (buffer-file-name thisbuf) ""))))))
                              (t
                               (ignore-errors
                                 (push (cons (if (eq var 'eval)
@@ -3535,8 +3564,9 @@ It is dangerous if either of these conditions are met:
             (since (nth 2 o)))
         (message "%s is obsolete%s; %s"
                  var (if since (format " (since %s)" since))
-                 (if (stringp instead) instead
-                   (format "use `%s' instead" instead)))))))
+                 (if (stringp instead)
+                     (substitute-command-keys instead)
+                   (format-message "use `%s' instead" instead)))))))
 
 (defun hack-one-local-variable (var val)
   "Set local variable VAR with value VAL.
@@ -3820,7 +3850,7 @@ This does nothing if either `enable-local-variables' or
              (if (eq (car elt) 'coding)
                   (unless hack-dir-local-variables--warned-coding
                     (setq hack-dir-local-variables--warned-coding t)
-                    (display-warning :warning
+                    (display-warning 'files
                                      "Coding cannot be specified by dir-locals"))
                (unless (memq (car elt) '(eval mode))
                  (setq dir-local-variables-alist
@@ -3842,7 +3872,7 @@ directories."
 However, the mode will not be changed if
 \(1) a local variables list or the `-*-' line specifies a major mode, or
 \(2) the current major mode is a \"special\" mode,
-    not suitable for ordinary files, or
+    not suitable for ordinary files, or
 \(3) the new file name does not particularly specify any mode."
   :type 'boolean
   :group 'editing-basics)
@@ -3931,17 +3961,19 @@ the old visited file has been renamed to the new name FILENAME."
           (make-local-variable 'backup-inhibited)
           (setq backup-inhibited t)))
     (let ((oauto buffer-auto-save-file-name))
-      ;; If auto-save was not already on, turn it on if appropriate.
-      (if (not buffer-auto-save-file-name)
-         (and buffer-file-name auto-save-default
-              (auto-save-mode t))
-       ;; If auto save is on, start using a new name.
-       ;; We deliberately don't rename or delete the old auto save
-       ;; for the old visited file name.  This is because perhaps
-       ;; the user wants to save the new state and then compare with the
-       ;; previous state from the auto save file.
-       (setq buffer-auto-save-file-name
-             (make-auto-save-file-name)))
+      (cond ((null filename)
+            (setq buffer-auto-save-file-name nil))
+           ((not buffer-auto-save-file-name)
+            ;; If auto-save was not already on, turn it on if appropriate.
+            (and buffer-file-name auto-save-default (auto-save-mode t)))
+           (t
+            ;; If auto save is on, start using a new name. We
+            ;; deliberately don't rename or delete the old auto save
+            ;; for the old visited file name.  This is because
+            ;; perhaps the user wants to save the new state and then
+            ;; compare with the previous state from the auto save
+            ;; file.
+            (setq buffer-auto-save-file-name (make-auto-save-file-name))))
       ;; Rename the old auto save file if any.
       (and oauto buffer-auto-save-file-name
           (file-exists-p oauto)
@@ -4006,7 +4038,8 @@ Interactively, confirmation is required unless you supply a prefix argument."
             (not (and (eq (framep-on-display) 'ns)
                       (listp last-nonmenu-event)
                       use-dialog-box))
-            (or (y-or-n-p (format "File `%s' exists; overwrite? " filename))
+            (or (y-or-n-p (format-message
+                            "File `%s' exists; overwrite? " filename))
                 (user-error "Canceled")))
        (set-visited-file-name filename (not confirm))))
   (set-buffer-modified-p t)
@@ -4017,7 +4050,7 @@ Interactively, confirmation is required unless you supply a prefix argument."
   (save-buffer)
   ;; It's likely that the VC status at the new location is different from
   ;; the one at the old location.
-  (vc-find-file-hook))
+  (vc-refresh-state))
 \f
 (defun file-extended-attributes (filename)
   "Return an alist of extended attributes of file FILENAME.
@@ -4031,14 +4064,19 @@ such as SELinux context, list of ACL entries, etc."
   "Set extended attributes of file FILENAME to ATTRIBUTES.
 
 ATTRIBUTES must be an alist of file attributes as returned by
-`file-extended-attributes'."
-  (dolist (elt attributes)
-    (let ((attr (car elt))
-         (val (cdr elt)))
-      (cond ((eq attr 'acl)
-            (set-file-acl filename val))
-           ((eq attr 'selinux-context)
-            (set-file-selinux-context filename val))))))
+`file-extended-attributes'.
+Value is t if the function succeeds in setting the attributes."
+  (let (result rv)
+    (dolist (elt attributes)
+      (let ((attr (car elt))
+           (val (cdr elt)))
+       (cond ((eq attr 'acl)
+               (setq rv (set-file-acl filename val)))
+             ((eq attr 'selinux-context)
+               (setq rv (set-file-selinux-context filename val))))
+        (setq result (or result rv))))
+
+    result))
 \f
 (defun backup-buffer ()
   "Make a backup of the disk file visited by the current buffer, if appropriate.
@@ -4058,80 +4096,75 @@ on the original file; this means that the caller, after saving
 the buffer, should change the extended attributes of the new file
 to agree with the old attributes.
 BACKUPNAME is the backup file name, which is the old file renamed."
-  (if (and make-backup-files (not backup-inhibited)
-          (not buffer-backed-up)
-          (file-exists-p buffer-file-name)
-          (memq (aref (elt (file-attributes buffer-file-name) 8) 0)
-                '(?- ?l)))
-      (let ((real-file-name buffer-file-name)
-           backup-info backupname targets setmodes)
+  (when (and make-backup-files (not backup-inhibited) (not buffer-backed-up))
+    (let ((attributes (file-attributes buffer-file-name)))
+      (when (and attributes (memq (aref (elt attributes 8) 0) '(?- ?l)))
        ;; If specified name is a symbolic link, chase it to the target.
-       ;; Thus we make the backups in the directory where the real file is.
-       (setq real-file-name (file-chase-links real-file-name))
-       (setq backup-info (find-backup-file-name real-file-name)
-             backupname (car backup-info)
-             targets (cdr backup-info))
-       ;; (if (file-directory-p buffer-file-name)
-       ;;     (error "Cannot save buffer in directory %s" buffer-file-name))
-       (if backup-info
-           (condition-case ()
-               (let ((delete-old-versions
-                      ;; If have old versions to maybe delete,
-                      ;; ask the user to confirm now, before doing anything.
-                      ;; But don't actually delete til later.
-                      (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)))))
-                     (modes (file-modes buffer-file-name))
-                     (extended-attributes
-                      (file-extended-attributes buffer-file-name)))
-                 ;; Actually write the back up file.
-                 (condition-case ()
-                     (if (or file-precious-flag
-    ;                        (file-symlink-p buffer-file-name)
-                             backup-by-copying
-                             ;; Don't rename a suid or sgid file.
-                             (and modes (< 0 (logand modes #o6000)))
-                             (not (file-writable-p (file-name-directory real-file-name)))
-                             (and backup-by-copying-when-linked
-                                  (> (file-nlinks real-file-name) 1))
-                             (and (or backup-by-copying-when-mismatch
-                                      (integerp backup-by-copying-when-privileged-mismatch))
-                                  (let ((attr (file-attributes real-file-name)))
-                                    (and (or backup-by-copying-when-mismatch
-                                             (and (integerp (nth 2 attr))
-                                                  (integerp backup-by-copying-when-privileged-mismatch)
-                                                  (<= (nth 2 attr) backup-by-copying-when-privileged-mismatch)))
-                                         (not (file-ownership-preserved-p
-                                               real-file-name t))))))
-                         (backup-buffer-copy real-file-name
-                                             backupname modes
-                                             extended-attributes)
-                       ;; rename-file should delete old backup.
-                       (rename-file real-file-name backupname t)
-                       (setq setmodes (list modes extended-attributes
-                                            backupname)))
-                   (file-error
-                    ;; 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)
-                    (backup-buffer-copy real-file-name backupname
-                                        modes extended-attributes)))
-                 (setq buffer-backed-up t)
-                 ;; Now delete the old versions, if desired.
-                 (if delete-old-versions
-                     (while targets
-                       (condition-case ()
-                           (delete-file (car targets))
-                         (file-error nil))
-                       (setq targets (cdr targets))))
-                 setmodes)
-           (file-error nil))))))
+       ;; This makes backups in the directory where the real file is.
+       (let* ((real-file-name (file-chase-links buffer-file-name))
+              (backup-info (find-backup-file-name real-file-name)))
+         (when backup-info
+           (let* ((backupname (car backup-info))
+                  (targets (cdr backup-info))
+                  (old-versions
+                   ;; If have old versions to maybe delete,
+                   ;; ask the user to confirm now, before doing anything.
+                   ;; But don't actually delete til later.
+                   (and targets
+                        (booleanp delete-old-versions)
+                        (or delete-old-versions
+                            (y-or-n-p
+                             (format "Delete excess backup versions of %s? "
+                                     real-file-name)))
+                        targets))
+                  (modes (file-modes buffer-file-name))
+                  (extended-attributes
+                   (file-extended-attributes buffer-file-name))
+                  (copy-when-priv-mismatch
+                   backup-by-copying-when-privileged-mismatch)
+                  (make-copy
+                   (or file-precious-flag backup-by-copying
+                       ;; Don't rename a suid or sgid file.
+                       (and modes (< 0 (logand modes #o6000)))
+                       (not (file-writable-p
+                             (file-name-directory real-file-name)))
+                       (and backup-by-copying-when-linked
+                            (< 1 (file-nlinks real-file-name)))
+                       (and (or backup-by-copying-when-mismatch
+                                (and (integerp copy-when-priv-mismatch)
+                                     (let ((attr (file-attributes
+                                                  real-file-name
+                                                  'integer)))
+                                       (<= (nth 2 attr)
+                                           copy-when-priv-mismatch))))
+                            (not (file-ownership-preserved-p real-file-name
+                                                             t)))))
+                  setmodes)
+             (condition-case ()
+                 (progn
+                   ;; Actually make the backup file.
+                   (if make-copy
+                       (backup-buffer-copy real-file-name backupname
+                                           modes extended-attributes)
+                     ;; rename-file should delete old backup.
+                     (rename-file real-file-name backupname t)
+                     (setq setmodes (list modes extended-attributes
+                                          backupname)))
+                   (setq buffer-backed-up t)
+                   ;; Now delete the old versions, if desired.
+                   (dolist (old-version old-versions)
+                     (delete-file old-version)))
+               (file-error nil))
+             ;; If trouble writing the backup, write it in .emacs.d/%backup%.
+             (when (not buffer-backed-up)
+               (setq backupname (locate-user-emacs-file "%backup%~"))
+               (message "Cannot write backup file; backing up in %s"
+                        backupname)
+               (sleep-for 1)
+               (backup-buffer-copy real-file-name backupname
+                                   modes extended-attributes)
+               (setq buffer-backed-up t))
+             setmodes)))))))
 
 (defun backup-buffer-copy (from-name to-name modes extended-attributes)
   ;; Create temp files with strict access rights.  It's easy to
@@ -4224,8 +4257,8 @@ the group would be preserved too."
 
 (defun file-name-sans-extension (filename)
   "Return FILENAME sans final \"extension\".
-The extension, in a file name, is the part that follows the last `.',
-except that a leading `.', if any, doesn't count."
+The extension, in a file name, is the part that begins with the last `.',
+except that a leading `.' of the file name, if there is one, doesn't count."
   (save-match-data
     (let ((file (file-name-sans-versions (file-name-nondirectory filename)))
          directory)
@@ -4240,15 +4273,16 @@ except that a leading `.', if any, doesn't count."
 
 (defun file-name-extension (filename &optional period)
   "Return FILENAME's final \"extension\".
-The extension, in a file name, is the part that follows the last `.',
-excluding version numbers and backup suffixes,
-except that a leading `.', if any, doesn't count.
+The extension, in a file name, is the part that begins with the last `.',
+excluding version numbers and backup suffixes, except that a leading `.'
+of the file name, if there is one, doesn't count.
 Return nil for extensionless file names such as `foo'.
 Return the empty string for file names such as `foo.'.
 
-If PERIOD is non-nil, then the returned value includes the period
-that delimits the extension, and if FILENAME has no extension,
-the value is \"\"."
+By default, the returned value excludes the period that starts the
+extension, but if the optional argument PERIOD is non-nil, the period
+is included in the value, and in that case, if FILENAME has no
+extension, the value is \"\"."
   (save-match-data
     (let ((file (file-name-sans-versions (file-name-nondirectory filename))))
       (if (and (string-match "\\.[^.]*\\'" file)
@@ -4639,9 +4673,12 @@ See the subroutine `basic-save-buffer' for more information."
     ;; then Rmail-mbox never displays it due to buffer swapping.  If
     ;; the test is ever re-introduced, be sure to handle saving of
     ;; Rmail files.
-    (if (and modp (buffer-file-name) (not noninteractive))
+    (if (and modp
+             (buffer-file-name)
+             (not noninteractive)
+             (not save-silently))
        (message "Saving file %s..." (buffer-file-name)))
-    (basic-save-buffer)
+    (basic-save-buffer (called-interactively-p 'any))
     (and modp (memq arg '(4 64)) (setq buffer-backed-up nil))))
 
 (defun delete-auto-save-file-if-necessary (&optional force)
@@ -4683,14 +4720,14 @@ in such cases.")
 (make-variable-buffer-local 'save-buffer-coding-system)
 (put 'save-buffer-coding-system 'permanent-local t)
 
-(defun basic-save-buffer ()
+(defun basic-save-buffer (&optional called-interactively)
   "Save the current buffer in its visited file, if it has been modified.
 The hooks `write-contents-functions' and `write-file-functions' get a chance
 to do the job of saving; if they do not, then the buffer is saved in
 the visited file in the usual way.
 Before and after saving the buffer, this function runs
 `before-save-hook' and `after-save-hook', respectively."
-  (interactive)
+  (interactive '(called-interactively))
   (save-current-buffer
     ;; In an indirect buffer, save its base buffer instead.
     (if (buffer-base-buffer)
@@ -4713,8 +4750,9 @@ 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 (format-message
+                                         "File `%s' exists; overwrite? "
+                                         filename))
                         (error "Canceled"))))
                 (set-visited-file-name filename)))
          (or (verify-visited-file-modtime (current-buffer))
@@ -4754,7 +4792,8 @@ Before and after saving the buffer, this function runs
                            (expand-file-name buffer-file-name))))
                  (unless (file-exists-p dir)
                    (if (y-or-n-p
-                        (format "Directory `%s' does not exist; create? " dir))
+                        (format-message
+                          "Directory `%s' does not exist; create? " dir))
                        (make-directory dir t)
                      (error "Canceled")))
                  (setq setmodes (basic-save-buffer-1))))
@@ -4781,7 +4820,9 @@ Before and after saving the buffer, this function runs
          ;; Support VC `implicit' locking.
          (vc-after-save)
          (run-hooks 'after-save-hook))
-      (or noninteractive (message "(No changes need to be saved)")))))
+      (or noninteractive
+          (not called-interactively)
+          (files--message "(No changes need to be saved)")))))
 
 ;; This does the "real job" of writing a buffer into its visited file
 ;; and making a backup file.  This is what is normally done
@@ -4825,9 +4866,9 @@ Before and after saving the buffer, this function runs
                    (file-exists-p buffer-file-name)
                    (> (file-nlinks buffer-file-name) 1)
                    (or dir-writable
-                       (error (concat (format
-                                       "Directory %s write-protected; " dir)
-                                      "cannot break hardlink when saving")))))
+                       (error (concat "Directory %s write-protected; "
+                                      "cannot break hardlink when saving")
+                              dir))))
          ;; Write temp name, then rename it.
          ;; This requires write access to the containing dir,
          ;; which is why we don't try it if we don't have that access.
@@ -4854,9 +4895,10 @@ Before and after saving the buffer, this function runs
                                ;; Pass in nil&nil rather than point-min&max
                                ;; cause we're saving the whole buffer.
                                ;; write-region-annotate-functions may use it.
-                              (write-region nil nil
-                                            tempname nil  realname
-                                            buffer-file-truename 'excl)
+                               (write-region nil nil
+                                             tempname nil  realname
+                                             buffer-file-truename 'excl)
+                               (when save-silently (message nil))
                               nil)
                           (file-already-exists t))
                    ;; The file was somehow created by someone else between
@@ -4901,8 +4943,9 @@ Before and after saving the buffer, this function runs
                 ;; Pass in nil&nil rather than point-min&max to indicate
                 ;; we're saving the buffer rather than just a region.
                 ;; write-region-annotate-functions may make us of it.
-               (write-region nil nil
-                             buffer-file-name nil t buffer-file-truename)
+                (write-region nil nil
+                              buffer-file-name nil t buffer-file-truename)
+                (when save-silently (message nil))
                (setq success t))
            ;; If we get an error writing the new file, and we made
            ;; the backup by renaming, undo the backing-up.
@@ -5022,17 +5065,18 @@ change the additional actions you can take on files."
       (or queried (> files-done 0) abbrevs-done
          (cond
           ((null autosaved-buffers)
-           (message "(No files need saving)"))
+            (when (called-interactively-p 'any)
+              (files--message "(No files need saving)")))
           ((= (length autosaved-buffers) 1)
-           (message "(Saved %s)" (car autosaved-buffers)))
+           (files--message "(Saved %s)" (car autosaved-buffers)))
           (t
-           (message "(Saved %d files: %s)"
-                    (length autosaved-buffers)
-                    (mapconcat 'identity autosaved-buffers ", "))))))))
+           (files--message "(Saved %d files: %s)"
+                            (length autosaved-buffers)
+                            (mapconcat 'identity autosaved-buffers ", "))))))))
 \f
 (defun clear-visited-file-modtime ()
   "Clear out records of last mod time of visited file.
-Next attempt to save will certainly not complain of a discrepancy."
+Next attempt to save will not complain of a discrepancy."
   (set-visited-file-modtime 0))
 
 (defun not-modified (&optional arg)
@@ -5043,8 +5087,8 @@ It is not a good idea to use this function in Lisp programs, because it
 prints a message in the minibuffer.  Instead, use `set-buffer-modified-p'."
   (declare (interactive-only set-buffer-modified-p))
   (interactive "P")
-  (message (if arg "Modification-flag set"
-              "Modification-flag cleared"))
+  (files--message (if arg "Modification-flag set"
+                    "Modification-flag cleared"))
   (set-buffer-modified-p arg))
 
 (defun toggle-read-only (&optional arg interactive)
@@ -5078,7 +5122,8 @@ instead of any buffer contents; END is ignored.
 This does character code conversion and applies annotations
 like `write-region' does."
   (interactive "r\nFAppend to file: ")
-  (write-region start end filename t))
+  (prog1 (write-region start end filename t)
+    (when save-silently (message nil))))
 
 (defun file-newest-backup (filename)
   "Return most recent backup file for FILENAME or nil if no backups exist."
@@ -5191,8 +5236,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")))
+               (format-message "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
@@ -5254,7 +5299,12 @@ Return nil if DIR is not an existing directory."
              dir  (file-truename dir))
        (let ((ls1 (split-string file "/" t))
              (ls2 (split-string dir  "/" t))
-             (root (if (string-match "\\`/" file) "/" ""))
+             (root
+               (cond
+                ;; A UNC on Windows systems, or a "super-root" on Apollo.
+                ((string-match "\\`//" file) "//")
+                ((string-match "\\`/" file) "/")
+                (t "")))
              (mismatch nil))
          (while (and ls1 ls2 (not mismatch))
            (if (string-equal (car ls1) (car ls2))
@@ -5394,6 +5444,7 @@ This function only handles buffers that are visiting files.
 Non-file buffers need a custom function"
   (and buffer-file-name
        (file-readable-p buffer-file-name)
+       (not (buffer-modified-p (current-buffer)))
        (not (verify-visited-file-modtime (current-buffer)))))
 
 (defvar buffer-stale-function #'buffer-stale--default-function
@@ -6012,6 +6063,7 @@ by `sh' are supported."
 (defun file-expand-wildcards (pattern &optional full)
   "Expand wildcard pattern PATTERN.
 This returns a list of file names which match the pattern.
+Files are sorted in `string<' order.
 
 If PATTERN is written as an absolute file name,
 the values are absolute also.
@@ -6095,7 +6147,7 @@ and `list-directory-verbose-switches'."
 
 PATTERN is assumed to represent a file-name wildcard suitable for the
 underlying filesystem.  For Unix and GNU/Linux, each character from the
-set [ \\t\\n;<>&|()`'\"#$] is quoted with a backslash; for DOS/Windows, all
+set [ \\t\\n;<>&|()\\=`\\='\"#$] is quoted with a backslash; for DOS/Windows, all
 the parts of the pattern which don't include wildcard characters are
 quoted with double quotes.
 
@@ -6170,7 +6222,7 @@ 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)
+  (unless (file-remote-p (expand-file-name dir))
     ;; Try to find the number of free blocks.  Non-Posix systems don't
     ;; always have df, but might have an equivalent system call.
     (if (fboundp 'file-system-info)
@@ -6470,7 +6522,7 @@ normally equivalent short `-D' option is just passed on to
                  (setq error-lines (nreverse error-lines))
                  ;; Now read the numeric positions of file names.
                  (goto-char linebeg)
-                 (forward-word 1)
+                 (forward-word-strictly 1)
                  (forward-char 3)
                  (while (< (point) end)
                    (let ((start (insert-directory-adj-pos
@@ -6745,8 +6797,8 @@ If CHAR is in [Xugo], the value is taken from FROM (or 0 if omitted)."
   (cond ((= char ?r) #o0444)
        ((= char ?w) #o0222)
        ((= char ?x) #o0111)
-       ((= char ?s) #o1000)
-       ((= char ?t) #o6000)
+       ((= char ?s) #o6000)
+       ((= char ?t) #o1000)
        ;; Rights relative to the previous file modes.
        ((= char ?X) (if (= (logand from #o111) 0) 0 #o0111))
        ((= char ?u) (let ((uright (logand #o4700 from)))
@@ -6802,7 +6854,7 @@ as in \"og+rX-w\"."
                                  (mapcar 'file-modes-char-to-who
                                          (match-string 1 modes)))))
              (when (= num-who 0)
-               (setq num-who (default-file-modes)))
+               (setq num-who (logior #o7000 (default-file-modes))))
              (setq num-modes
                    (file-modes-rights-to-number (substring modes (match-end 1))
                                                 num-who num-modes)
@@ -6812,7 +6864,7 @@ as in \"og+rX-w\"."
 
 (defun read-file-modes (&optional prompt orig-file)
   "Read file modes in octal or symbolic notation and return its numeric value.
-PROMPT is used as the prompt, default to `File modes (octal or symbolic): '.
+PROMPT is used as the prompt, default to \"File modes (octal or symbolic): \".
 ORIG-FILE is the name of a file on whose mode bits to base returned
 permissions if what user types requests to add, remove, or set permissions
 based on existing mode bits, as in \"og+rX-w\"."