Include interactive-only information in describe-function output
[bpt/emacs.git] / lisp / files.el
index 0695862..a17677b 100644 (file)
@@ -1,8 +1,8 @@
-;;; files.el --- file input and output commands for Emacs
+;;; files.el --- file input and output commands for Emacs  -*- lexical-binding:t -*-
 
-;; Copyright (C) 1985-1987, 1992-2013 Free Software Foundation, Inc.
+;; Copyright (C) 1985-1987, 1992-2014 Free Software Foundation, Inc.
 
-;; Maintainer: FSF
+;; Maintainer: emacs-devel@gnu.org
 ;; Package: emacs
 
 ;; This file is part of GNU Emacs.
@@ -96,9 +96,9 @@ The choice of renaming or copying is controlled by the variables
 ;; Do this so that local variables based on the file name
 ;; are not overridden by the major mode.
 (defvar backup-inhibited nil
-  "Non-nil means don't make a backup, regardless of the other parameters.
-This variable is intended for use by making it local to a buffer.
-But it is local only if you make it local.")
+  "If non-nil, backups will be inhibited.
+This variable is intended for use by making it local to a buffer,
+but it is not an automatically buffer-local variable.")
 (put 'backup-inhibited 'permanent-local t)
 
 (defcustom backup-by-copying nil
@@ -159,9 +159,11 @@ under another name, you get the existing buffer instead of a new buffer."
   :group 'find-file)
 
 (defcustom find-file-visit-truename nil
-  "Non-nil means visit a file under its truename.
-The truename of a file is found by chasing all links
-both at the file level and at the levels of the containing directories."
+  "Non-nil means visiting a file uses its truename as the visited-file name.
+That is, the buffer visiting the file has the truename as the
+value of `buffer-file-name'.  The truename of a file is found by
+chasing all links both at the file level and at the levels of the
+containing directories."
   :type 'boolean
   :group 'find-file)
 (put 'find-file-visit-truename 'safe-local-variable 'booleanp)
@@ -206,7 +208,7 @@ have fast storage with limited space, such as a RAM disk."
 (declare-function msdos-long-file-names "msdos.c")
 (declare-function w32-long-file-name "w32proc.c")
 (declare-function dired-get-filename "dired" (&optional localp no-error-if-not-filep))
-(declare-function dired-unmark "dired" (arg))
+(declare-function dired-unmark "dired" (arg &optional interactive))
 (declare-function dired-do-flagged-delete "dired" (&optional nomessage))
 (declare-function dos-8+3-filename "dos-fns" (filename))
 (declare-function dosified-file-name "dos-fns" (file-name))
@@ -248,10 +250,12 @@ See also: `break-hardlink-on-save'."
   :group 'backup)
 
 (defcustom break-hardlink-on-save nil
-  "Non-nil means when saving a file that exists under several names
-\(i.e., has multiple hardlinks), break the hardlink associated with
-`buffer-file-name' and write to a new file, so that the other
-instances of the file are not affected by the save.
+  "Whether to allow breaking hardlinks when saving files.
+If non-nil, then when saving a file that exists under several
+names \(i.e., has multiple hardlinks), break the hardlink
+associated with `buffer-file-name' and write to a new file, so
+that the other instances of the file are not affected by the
+save.
 
 If `buffer-file-name' refers to a symlink, do not break the symlink.
 
@@ -316,6 +320,7 @@ A value of nil means don't add newlines.
 
 Certain major modes set this locally to the value obtained
 from `mode-require-final-newline'."
+  :safe #'symbolp
   :type '(choice (const :tag "When visiting" visit)
                 (const :tag "When saving" t)
                 (const :tag "When visiting or saving" visit-save)
@@ -742,8 +747,8 @@ The path separator is colon in GNU and GNU-like systems."
 
 (defun locate-file (filename path &optional suffixes predicate)
   "Search for FILENAME through PATH.
-If found, return the absolute file name of FILENAME, with its suffixes;
-otherwise return nil.
+If found, return the absolute file name of FILENAME; otherwise
+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
@@ -915,6 +920,57 @@ which we're looking."
              (setq file nil))))
     (if root (file-name-as-directory root))))
 
+(defcustom user-emacs-directory-warning t
+  "Non-nil means warn if cannot access `user-emacs-directory'.
+Set this to nil at your own risk..."
+  :type 'boolean
+  :group 'initialization
+  :version "24.4")
+
+(defun locate-user-emacs-file (new-name &optional old-name)
+  "Return an absolute per-user Emacs-specific file name.
+If NEW-NAME exists in `user-emacs-directory', return it.
+Else if OLD-NAME is non-nil and ~/OLD-NAME exists, return ~/OLD-NAME.
+Else return NEW-NAME in `user-emacs-directory', creating the
+directory if it does not exist."
+  (convert-standard-filename
+   (let* ((home (concat "~" (or init-file-user "")))
+         (at-home (and old-name (expand-file-name old-name home)))
+          (bestname (abbreviate-file-name
+                     (expand-file-name new-name user-emacs-directory))))
+     (if (and at-home (not (file-readable-p bestname))
+              (file-readable-p at-home))
+        at-home
+       ;; Make sure `user-emacs-directory' exists,
+       ;; unless we're in batch mode or dumping Emacs.
+       (or noninteractive
+          purify-flag
+          (let (errtype)
+            (if (file-directory-p user-emacs-directory)
+                (or (file-accessible-directory-p user-emacs-directory)
+                    (setq errtype "access"))
+              (let ((umask (default-file-modes)))
+                (unwind-protect
+                    (progn
+                      (set-default-file-modes ?\700)
+                      (condition-case nil
+                          (make-directory user-emacs-directory)
+                        (error (setq errtype "create"))))
+                  (set-default-file-modes umask))))
+            (when (and errtype
+                       user-emacs-directory-warning
+                       (not (get 'user-emacs-directory-warning 'this-session)))
+              ;; Only warn once per Emacs session.
+              (put 'user-emacs-directory-warning 'this-session t)
+              (display-warning 'initialization
+                               (format "\
+Unable to %s `user-emacs-directory' (%s).
+Any data that would normally be written there may be lost!
+If you never want to see this message again,
+customize the variable `user-emacs-directory-warning'."
+                                       errtype user-emacs-directory)))))
+       bestname))))
+
 
 (defun executable-find (command)
   "Search for COMMAND in `exec-path' and return the absolute file name.
@@ -1373,7 +1429,7 @@ You can visit files on remote machines by specifying something
 like /ssh:SOME_REMOTE_MACHINE:FILE for the file name.  You can
 also visit local files as a different user by specifying
 /sudo::FILE for the file name.
-See the Info node `(tramp)Filename Syntax' in the Tramp Info
+See the Info node `(tramp)File name Syntax' in the Tramp Info
 manual, for more about this.
 
 Interactively, or if WILDCARDS is non-nil in a call from Lisp,
@@ -1602,13 +1658,16 @@ killed."
   "Create a suitably named buffer for visiting FILENAME, and return it.
 FILENAME (sans directory) is used unchanged if that name is free;
 otherwise a string <2> or <3> or ... is appended to get an unused name.
-Spaces at the start of FILENAME (sans directory) are removed."
+
+Emacs treats buffers whose names begin with a space as internal buffers.
+To avoid confusion when visiting a file whose name begins with a space,
+this function prepends a \"|\" to the final result if necessary."
   (let ((lastname (file-name-nondirectory filename)))
     (if (string= lastname "")
        (setq lastname filename))
-    (save-match-data
-      (string-match "^ *\\(.*\\)" lastname)
-      (generate-new-buffer (match-string 1 lastname)))))
+    (generate-new-buffer (if (string-match-p "\\` " lastname)
+                            (concat "|" lastname)
+                          lastname))))
 
 (defun generate-new-buffer (name)
   "Create and return a buffer with a name based on NAME.
@@ -1851,21 +1910,22 @@ the various files."
                              (eq read-only buffer-file-read-only)
                              (eq read-only buffer-read-only))
                    (when (or nowarn
-                             (let ((question
-                                    (format "File %s is %s on disk.  Change buffer mode? "
-                                            buffer-file-name
-                                            (if read-only "read-only" "writable"))))
+                             (let* ((new-status
+                                     (if read-only "read-only" "writable"))
+                                    (question
+                                     (format "File %s is %s on disk.  Make buffer %s, too? "
+                                             buffer-file-name
+                                             new-status new-status)))
                                (y-or-n-p question)))
                      (setq buffer-read-only read-only)))
                  (setq buffer-file-read-only read-only))
 
-               (when (and (not (eq (not (null rawfile))
-                                   (not (null find-file-literally))))
-                          (not nonexistent)
-                          ;; It is confusing to ask whether to visit
-                          ;; non-literally if they have the file in
-                          ;; hexl-mode or image-mode.
-                          (not (memq major-mode '(hexl-mode image-mode))))
+               (unless (or (eq (null rawfile) (null find-file-literally))
+                           nonexistent
+                           ;; It is confusing to ask whether to visit
+                           ;; non-literally if they have the file in
+                           ;; hexl-mode or image-mode.
+                           (memq major-mode '(hexl-mode image-mode)))
                  (if (buffer-modified-p)
                      (if (y-or-n-p
                           (format
@@ -1986,8 +2046,7 @@ Do you want to revisit the file normally now? ")
            (set-buffer-multibyte nil)
            (setq buffer-file-coding-system 'no-conversion)
            (set-buffer-major-mode buf)
-           (make-local-variable 'find-file-literally)
-           (setq find-file-literally t))
+           (setq-local find-file-literally t))
        (after-find-file error (not nowarn)))
       (current-buffer))))
 \f
@@ -2030,6 +2089,7 @@ This function ensures that none of these modifications will take place."
 This function is meant for the user to run interactively.
 Don't call it from programs!  Use `insert-file-contents-literally' instead.
 \(Its calling sequence is different; see its documentation)."
+  (declare (interactive-only insert-file-contents-literally))
   (interactive "*fInsert file literally: ")
   (insert-file-1 filename #'insert-file-contents-literally))
 
@@ -2175,7 +2235,7 @@ not set local variables (though we do notice a mode specified with -*-.)
 or from Lisp without specifying the optional argument FIND-FILE;
 in that case, this function acts as if `enable-local-variables' were t."
   (interactive)
-  (funcall (or (default-value 'major-mode) 'fundamental-mode))
+  (fundamental-mode)
   (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:".
@@ -2267,14 +2327,18 @@ since only a single case-insensitive search through the alist is made."
      ;; .PROCESSORNAME-gdbinit so that the host and target gdbinit files
      ;; don't interfere with each other.
      ("/\\.[a-z0-9-]*gdbinit" . gdb-script-mode)
+     ;; GDB 7.5 introduced OBJFILE-gdb.gdb script files; e.g. a file
+     ;; named 'emacs-gdb.gdb', if it exists, will be automatically
+     ;; loaded when GDB reads an objfile called 'emacs'.
+     ("-gdb\\.gdb" . 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)
      ("\\.scm\\.[0-9]*\\'" . scheme-mode)
      ("\\.[ck]?sh\\'\\|\\.shar\\'\\|/\\.z?profile\\'" . sh-mode)
      ("\\.bash\\'" . sh-mode)
-     ("\\(/\\|\\`\\)\\.\\(bash_profile\\|z?login\\|bash_login\\|z?logout\\)\\'" . sh-mode)
-     ("\\(/\\|\\`\\)\\.\\(bash_logout\\|shrc\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
+     ("\\(/\\|\\`\\)\\.\\(bash_\\(profile\\|history\\|log\\(in\\|out\\)\\)\\|z?log\\(in\\|out\\)\\)\\'" . sh-mode)
+     ("\\(/\\|\\`\\)\\.\\(shrc\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
      ("\\(/\\|\\`\\)\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
      ("\\.m?spec\\'" . sh-mode)
      ("\\.m[mes]\\'" . nroff-mode)
@@ -2313,7 +2377,7 @@ since only a single case-insensitive search through the alist is made."
      ("\\.\\(\
 arc\\|zip\\|lzh\\|lha\\|zoo\\|[jew]ar\\|xpi\\|rar\\|7z\\|\
 ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|7Z\\)\\'" . archive-mode)
-     ("\\.\\(sx[dmicw]\\|od[fgpst]\\|oxt\\)\\'" . archive-mode) ;OpenOffice.org
+     ("\\.oxt\\'" . archive-mode) ;(Open|Libre)Office extensions.
      ("\\.\\(deb\\|[oi]pk\\)\\'" . archive-mode) ; Debian/Opkg packages.
      ;; Mailer puts message to be edited in
      ;; /tmp/Re.... or Message
@@ -2445,34 +2509,22 @@ and `magic-mode-alist', which determines modes based on file contents.")
   (mapcar
    (lambda (l)
      (cons (purecopy (car l)) (cdr l)))
-   '(("perl" . perl-mode)
-     ("perl5" . perl-mode)
-     ("miniperl" . perl-mode)
-     ("wish" . tcl-mode)
-     ("wishx" . tcl-mode)
-     ("tcl" . tcl-mode)
-     ("tclsh" . tcl-mode)
+   '(("\\(mini\\)?perl5?" . perl-mode)
+     ("wishx?" . tcl-mode)
+     ("tcl\\(sh\\)?" . tcl-mode)
+     ("expect" . tcl-mode)
+     ("octave" . octave-mode)
      ("scm" . scheme-mode)
-     ("ash" . sh-mode)
-     ("bash" . sh-mode)
-     ("bash2" . sh-mode)
-     ("csh" . sh-mode)
-     ("dtksh" . sh-mode)
+     ("[acjkwz]sh" . sh-mode)
+     ("r?bash2?" . sh-mode)
+     ("dash" . sh-mode)
+     ("\\(dt\\|pd\\|w\\)ksh" . sh-mode)
      ("es" . sh-mode)
-     ("itcsh" . sh-mode)
-     ("jsh" . sh-mode)
-     ("ksh" . sh-mode)
+     ("i?tcsh" . sh-mode)
      ("oash" . sh-mode)
-     ("pdksh" . sh-mode)
-     ("rbash" . sh-mode)
      ("rc" . sh-mode)
      ("rpm" . sh-mode)
-     ("sh" . sh-mode)
-     ("sh5" . sh-mode)
-     ("tcsh" . sh-mode)
-     ("wksh" . sh-mode)
-     ("wsh" . sh-mode)
-     ("zsh" . sh-mode)
+     ("sh5?" . sh-mode)
      ("tail" . text-mode)
      ("more" . text-mode)
      ("less" . text-mode)
@@ -2483,9 +2535,10 @@ and `magic-mode-alist', which determines modes based on file contents.")
      ("emacs" . emacs-lisp-mode)))
   "Alist mapping interpreter names to major modes.
 This is used for files whose first lines match `auto-mode-interpreter-regexp'.
-Each element looks like (INTERPRETER . MODE).
-If INTERPRETER matches the name of the interpreter specified in the first line
-of a script, mode MODE is enabled.
+Each element looks like (REGEXP . MODE).
+If \\\\`REGEXP\\\\' matches the name (minus any directory part) of
+the interpreter specified in the first line of a script, enable
+major mode MODE.
 
 See also `auto-mode-alist'.")
 
@@ -2680,19 +2733,23 @@ we don't actually set it to the same mode the buffer already has."
     ;; If we didn't, look for an interpreter specified in the first line.
     ;; As a special case, allow for things like "#!/bin/env perl", which
     ;; finds the interpreter anywhere in $PATH.
-    (unless done
-      (setq mode (save-excursion
-                  (goto-char (point-min))
-                  (if (looking-at auto-mode-interpreter-regexp)
-                      (match-string 2)
-                    ""))
-           ;; Map interpreter name to a mode, signaling we're done at the
-           ;; same time.
-           done (assoc (file-name-nondirectory mode)
-                       interpreter-mode-alist))
-      ;; If we found an interpreter mode to use, invoke it now.
-      (if done
-         (set-auto-mode-0 (cdr done) keep-mode-if-same)))
+    (and (not done)
+        (setq mode (save-excursion
+                     (goto-char (point-min))
+                     (if (looking-at auto-mode-interpreter-regexp)
+                         (match-string 2))))
+        ;; Map interpreter name to a mode, signaling we're done at the
+        ;; same time.
+        (setq done (assoc-default
+                    (file-name-nondirectory mode)
+                    (mapcar (lambda (e)
+                               (cons
+                                (format "\\`%s\\'" (car e))
+                                (cdr e)))
+                            interpreter-mode-alist)
+                    #'string-match-p))
+        ;; If we found an interpreter mode to use, invoke it now.
+        (set-auto-mode-0 done keep-mode-if-same))
     ;; Next try matching the buffer beginning against magic-mode-alist.
     (unless done
       (if (setq done (save-excursion
@@ -2759,7 +2816,9 @@ we don't actually set it to the same mode the buffer already has."
                                          (if (functionp re)
                                              (funcall re)
                                            (looking-at re)))))))
-         (set-auto-mode-0 done keep-mode-if-same)))))
+         (set-auto-mode-0 done keep-mode-if-same)))
+    (unless done
+      (set-buffer-major-mode (current-buffer)))))
 
 ;; When `keep-mode-if-same' is set, we are working on behalf of
 ;; set-visited-file-name.  In that case, if the major mode specified is the
@@ -3029,6 +3088,9 @@ n  -- to ignore the local variables list.")
          (prog1 (memq char '(?! ?\s ?y))
            (quit-window t)))))))
 
+(defconst hack-local-variable-regexp
+  "[ \t]*\\([^][;\"'?()\\ \t\n]+\\)[ \t]*:[ \t]*")
+
 (defun hack-local-variables-prop-line (&optional mode-only)
   "Return local variables specified in the -*- line.
 Returns an alist of elements (VAR . VAL), where VAR is a variable
@@ -3055,11 +3117,11 @@ mode, if there is one, otherwise nil."
               ;; (last ";" is optional).
               ;; If MODE-ONLY, just check for `mode'.
               ;; Otherwise, parse the -*- line into the RESULT alist.
-              (while (and (or (not mode-only)
-                              (not result))
-                          (< (point) end))
-                (unless (looking-at "[ \t]*\\([^ \t\n:]+\\)[ \t]*:[ \t]*")
-                  (message "Malformed mode-line")
+              (while (not (or (and mode-only result)
+                               (>= (point) end)))
+                (unless (looking-at hack-local-variable-regexp)
+                  (message "Malformed mode-line: %S"
+                            (buffer-substring-no-properties (point) end))
                   (throw 'malformed-line nil))
                 (goto-char (match-end 0))
                 ;; There used to be a downcase here,
@@ -3151,6 +3213,9 @@ DIR-NAME is the name of the associated directory.  Otherwise it is nil."
                   (assq-delete-all (car elt) file-local-variables-alist)))
           (push elt file-local-variables-alist)))))
 
+;; TODO?  Warn once per file rather than once per session?
+(defvar hack-local-variables--warned-lexical nil)
+
 (defun hack-local-variables (&optional mode-only)
   "Parse and put into effect this buffer's local variables spec.
 Uses `hack-local-variables-apply' to apply the variables.
@@ -3211,8 +3276,7 @@ local variables, but directory-local variables may still be applied."
                  (prefix
                   (concat "^" (regexp-quote
                                (buffer-substring (line-beginning-position)
-                                                 (match-beginning 0)))))
-                 beg)
+                                                 (match-beginning 0))))))
 
              (forward-line 1)
              (let ((startpos (point))
@@ -3247,18 +3311,16 @@ local variables, but directory-local variables may still be applied."
                    (forward-line 1))
                  (goto-char (point-min))
 
-                 (while (and (not (eobp))
-                             (or (not mode-only)
-                                 (not result)))
-                   ;; Find the variable name; strip whitespace.
-                   (skip-chars-forward " \t")
-                   (setq beg (point))
-                   (skip-chars-forward "^:\n")
-                   (if (eolp) (error "Missing colon in local variables entry"))
-                   (skip-chars-backward " \t")
-                   (let* ((str (buffer-substring beg (point)))
-                          (var (let ((read-circle nil))
-                                 (read str)))
+                 (while (not (or (eobp)
+                                  (and mode-only result)))
+                   ;; Find the variable name;
+                   (unless (looking-at hack-local-variable-regexp)
+                      (error "Malformed local variable line: %S"
+                             (buffer-substring-no-properties
+                              (point) (line-end-position))))
+                    (goto-char (match-end 1))
+                   (let* ((str (match-string 1))
+                          (var (intern str))
                           val val2)
                      (and (equal (downcase (symbol-name var)) "mode")
                           (setq var 'mode))
@@ -3275,13 +3337,21 @@ local variables, but directory-local variables may still be applied."
                                     "-minor\\'"
                                     (setq val2 (downcase (symbol-name val)))))
                               (setq result (intern (concat val2 "-mode"))))
-                       (unless (eq var 'coding)
-                         (condition-case nil
-                             (push (cons (if (eq var 'eval)
-                                             'eval
-                                           (indirect-variable var))
-                                         val) result)
-                           (error nil)))))
+                       (cond ((eq var 'coding))
+                             ((eq var 'lexical-binding)
+                              (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 ""))))))
+                             (t
+                              (ignore-errors
+                                (push (cons (if (eq var 'eval)
+                                                'eval
+                                              (indirect-variable var))
+                                            val) result))))))
                    (forward-line 1))))))))
       ;; Now we've read all the local variables.
       ;; If MODE-ONLY is non-nil, return whether the mode was specified.
@@ -3642,22 +3712,17 @@ FILE is the name of the file holding the variables to apply.
 The new class name is the same as the directory in which FILE
 is found.  Returns the new class name."
   (with-temp-buffer
-    ;; This is with-demoted-errors, but we want to mention dir-locals
-    ;; in any error message.
-    (let (err)
-      (condition-case err
-         (progn
-           (insert-file-contents file)
-           (unless (zerop (buffer-size))
-             (let* ((dir-name (file-name-directory file))
-                    (class-name (intern dir-name))
-                    (variables (let ((read-circle nil))
-                                 (read (current-buffer)))))
-               (dir-locals-set-class-variables class-name variables)
-               (dir-locals-set-directory-class dir-name class-name
-                                               (nth 5 (file-attributes file)))
-               class-name)))
-       (error (message "Error reading dir-locals: %S" err) nil)))))
+    (with-demoted-errors "Error reading dir-locals: %S"
+      (insert-file-contents file)
+      (unless (zerop (buffer-size))
+        (let* ((dir-name (file-name-directory file))
+               (class-name (intern dir-name))
+               (variables (let ((read-circle nil))
+                            (read (current-buffer)))))
+          (dir-locals-set-class-variables class-name variables)
+          (dir-locals-set-directory-class dir-name class-name
+                                          (nth 5 (file-attributes file)))
+          class-name)))))
 
 (defcustom enable-remote-dir-locals nil
   "Non-nil means dir-local variables will be applied to remote files."
@@ -3665,6 +3730,8 @@ is found.  Returns the new class name."
   :type 'boolean
   :group 'find-file)
 
+(defvar hack-dir-local-variables--warned-coding nil)
+
 (defun hack-dir-local-variables ()
   "Read per-directory local variables for the current buffer.
 Store the directory-local variables in `dir-local-variables-alist'
@@ -3696,8 +3763,10 @@ This does nothing if either `enable-local-variables' or
          (when variables
            (dolist (elt variables)
              (if (eq (car elt) 'coding)
-                 (display-warning :warning
-                                  "Coding cannot be specified by dir-locals")
+                  (unless hack-dir-local-variables--warned-coding
+                    (setq hack-dir-local-variables--warned-coding t)
+                    (display-warning :warning
+                                     "Coding cannot be specified by dir-locals"))
                (unless (memq (car elt) '(eval mode))
                  (setq dir-local-variables-alist
                        (assq-delete-all (car elt) dir-local-variables-alist)))
@@ -3878,6 +3947,10 @@ Interactively, confirmation is required unless you supply a prefix argument."
                                    (or buffer-file-name (buffer-name))))))
        (and confirm
             (file-exists-p filename)
+            ;; NS does its own confirm dialog.
+            (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))
                 (error "Canceled")))
        (set-visited-file-name filename (not confirm))))
@@ -4140,9 +4213,9 @@ FILENAME defaults to `buffer-file-name'."
   (file-name-sans-extension
    (file-name-nondirectory (or filename (buffer-file-name)))))
 
-(defcustom make-backup-file-name-function nil
+(defcustom make-backup-file-name-function
+  #'make-backup-file-name--default-function
   "A function to use instead of the default `make-backup-file-name'.
-A value of nil gives the default `make-backup-file-name' behavior.
 
 This could be buffer-local to do something special for specific
 files.  If you define it, you may need to change `backup-file-name-p'
@@ -4150,8 +4223,7 @@ and `file-name-sans-versions' too.
 
 See also `backup-directory-alist'."
   :group 'backup
-  :type '(choice (const :tag "Default" nil)
-                (function :tag "Your function")))
+  :type '(function :tag "Your function"))
 
 (defcustom backup-directory-alist nil
   "Alist of filename patterns and backup directory names.
@@ -4180,47 +4252,57 @@ ignored."
   "Default `backup-enable-predicate' function.
 Checks for files in `temporary-file-directory',
 `small-temporary-file-directory', and /tmp."
-  (not (or (let ((comp (compare-strings temporary-file-directory 0 nil
-                                       name 0 nil)))
-            ;; Directory is under temporary-file-directory.
-            (and (not (eq comp t))
-                 (< comp (- (length temporary-file-directory)))))
-          (let ((comp (compare-strings "/tmp" 0 nil
-                                       name 0 nil)))
-            ;; Directory is under /tmp.
-            (and (not (eq comp t))
-                 (< comp (- (length "/tmp")))))
-          (if small-temporary-file-directory
-              (let ((comp (compare-strings small-temporary-file-directory
-                                           0 nil
-                                           name 0 nil)))
-                ;; Directory is under small-temporary-file-directory.
-                (and (not (eq comp t))
-                     (< comp (- (length small-temporary-file-directory)))))))))
+  (let ((temporary-file-directory temporary-file-directory)
+       caseless)
+    ;; On MS-Windows, file-truename will convert short 8+3 aliases to
+    ;; their long file-name equivalents, so compare-strings does TRT.
+    (if (memq system-type '(ms-dos windows-nt))
+       (setq temporary-file-directory (file-truename temporary-file-directory)
+             name (file-truename name)
+             caseless t))
+    (not (or (let ((comp (compare-strings temporary-file-directory 0 nil
+                                         name 0 nil caseless)))
+              ;; Directory is under temporary-file-directory.
+              (and (not (eq comp t))
+                   (< comp (- (length temporary-file-directory)))))
+            (let ((comp (compare-strings "/tmp" 0 nil
+                                         name 0 nil)))
+              ;; Directory is under /tmp.
+              (and (not (eq comp t))
+                   (< comp (- (length "/tmp")))))
+            (if small-temporary-file-directory
+                (let ((comp (compare-strings small-temporary-file-directory
+                                             0 nil
+                                             name 0 nil caseless)))
+                  ;; Directory is under small-temporary-file-directory.
+                  (and (not (eq comp t))
+                       (< comp (- (length small-temporary-file-directory))))))))))
 
 (defun make-backup-file-name (file)
   "Create the non-numeric backup file name for FILE.
 Normally this will just be the file's name with `~' appended.
 Customization hooks are provided as follows.
 
-If the variable `make-backup-file-name-function' is non-nil, its value
-should be a function which will be called with FILE as its argument;
-the resulting name is used.
+The value of `make-backup-file-name-function' should be a function which
+will be called with FILE as its argument; the resulting name is used.
 
-Otherwise a match for FILE is sought in `backup-directory-alist'; see
+By default, a match for FILE is sought in `backup-directory-alist'; see
 the documentation of that variable.  If the directory for the backup
 doesn't exist, it is created."
-  (if make-backup-file-name-function
-      (funcall make-backup-file-name-function file)
-    (if (and (eq system-type 'ms-dos)
-            (not (msdos-long-file-names)))
-       (let ((fn (file-name-nondirectory file)))
-         (concat (file-name-directory file)
-                 (or (and (string-match "\\`[^.]+\\'" fn)
-                          (concat (match-string 0 fn) ".~"))
-                     (and (string-match "\\`[^.]+\\.\\(..?\\)?" fn)
-                          (concat (match-string 0 fn) "~")))))
-      (concat (make-backup-file-name-1 file) "~"))))
+  (funcall (or make-backup-file-name-function
+               #'make-backup-file-name--default-function)
+           file))
+
+(defun make-backup-file-name--default-function (file)
+  (if (and (eq system-type 'ms-dos)
+           (not (msdos-long-file-names)))
+      (let ((fn (file-name-nondirectory file)))
+        (concat (file-name-directory file)
+                (or (and (string-match "\\`[^.]+\\'" fn)
+                         (concat (match-string 0 fn) ".~"))
+                    (and (string-match "\\`[^.]+\\.\\(..?\\)?" fn)
+                         (concat (match-string 0 fn) "~")))))
+    (concat (make-backup-file-name-1 file) "~")))
 
 (defun make-backup-file-name-1 (file)
   "Subroutine of `make-backup-file-name' and `find-backup-file-name'."
@@ -4395,6 +4477,8 @@ Uses `backup-directory-alist' in the same way as does
   "Convert FILENAME to be relative to DIRECTORY (default: `default-directory').
 This function returns a relative file name which is equivalent to FILENAME
 when used with that default directory as the default.
+If FILENAME is a relative file name, it will be interpreted as existing in
+`default-directory'.
 If FILENAME and DIRECTORY lie on different machines or on different drives
 on a DOS/Windows machine, it returns FILENAME in expanded form."
   (save-match-data
@@ -4459,7 +4543,7 @@ on a DOS/Windows machine, it returns FILENAME in expanded form."
             ;; We matched FILENAME's directory equivalent.
             ancestor))))))
 \f
-(defun save-buffer (&optional args)
+(defun save-buffer (&optional arg)
   "Save current buffer in visited file if modified.
 Variations are described below.
 
@@ -4473,7 +4557,7 @@ Prefixed with three \\[universal-argument]'s, marks this version
  to become a backup when the next save is done,
  and unconditionally makes the previous version into a backup file.
 
-With a numeric argument of 0, never make the previous version
+With a numeric prefix argument of 0, never make the previous version
 into a backup file.
 
 If a file's name is FOO, the names of its numbered backup versions are
@@ -4497,9 +4581,9 @@ If `vc-make-backup-files' is nil, which is the default,
 See the subroutine `basic-save-buffer' for more information."
   (interactive "p")
   (let ((modp (buffer-modified-p))
-       (make-backup-files (or (and make-backup-files (not (eq args 0)))
-                              (memq args '(16 64)))))
-    (and modp (memq args '(16 64)) (setq buffer-backed-up nil))
+       (make-backup-files (or (and make-backup-files (not (eq arg 0)))
+                              (memq arg '(16 64)))))
+    (and modp (memq arg '(16 64)) (setq buffer-backed-up nil))
     ;; We used to display the message below only for files > 50KB, but
     ;; then Rmail-mbox never displays it due to buffer swapping.  If
     ;; the test is ever re-introduced, be sure to handle saving of
@@ -4507,7 +4591,7 @@ See the subroutine `basic-save-buffer' for more information."
     (if (and modp (buffer-file-name))
        (message "Saving file %s..." (buffer-file-name)))
     (basic-save-buffer)
-    (and modp (memq args '(4 64)) (setq buffer-backed-up nil))))
+    (and modp (memq arg '(4 64)) (setq buffer-backed-up nil))))
 
 (defun delete-auto-save-file-if-necessary (&optional force)
   "Delete auto-save file for current buffer if `delete-auto-save-files' is t.
@@ -4608,7 +4692,8 @@ Before and after saving the buffer, this function runs
                     (insert ?\n))))
            ;; Support VC version backups.
            (vc-before-save)
-           (run-hooks 'before-save-hook)
+           ;; Don't let errors prevent saving the buffer.
+           (with-demoted-errors (run-hooks 'before-save-hook))
            (or (run-hook-with-args-until-success 'write-contents-functions)
                (run-hook-with-args-until-success 'local-write-file-hooks)
                (run-hook-with-args-until-success 'write-file-functions)
@@ -4903,12 +4988,18 @@ change the additional actions you can take on files."
                     (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."
+  (set-visited-file-modtime 0))
+
 (defun not-modified (&optional arg)
   "Mark current buffer as unmodified, not needing to be saved.
 With prefix ARG, mark buffer as modified, so \\[save-buffer] will save.
 
 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"))
@@ -4928,6 +5019,7 @@ Set mark after the inserted text.
 This function is meant for the user to run interactively.
 Don't call it from programs!  Use `insert-file-contents' instead.
 \(Its calling sequence is different; see its documentation)."
+  (declare (interactive-only insert-file-contents))
   (interactive "*fInsert file: ")
   (insert-file-1 filename #'insert-file-contents))
 
@@ -5227,20 +5319,28 @@ comparison."
 
 \f
 (put 'revert-buffer-function 'permanent-local t)
-(defvar revert-buffer-function nil
+(defvar revert-buffer-function #'revert-buffer--default
   "Function to use to revert this buffer, or nil to do the default.
 The function receives two arguments IGNORE-AUTO and NOCONFIRM,
-which are the arguments that `revert-buffer' received.")
+which are the arguments that `revert-buffer' received.
+It also has access to the `preserve-modes' argument of `revert-buffer'
+via the `revert-buffer-preserve-modes' dynamic variable.")
 
 (put 'revert-buffer-insert-file-contents-function 'permanent-local t)
-(defvar revert-buffer-insert-file-contents-function nil
+(defvar revert-buffer-insert-file-contents-function
+  #'revert-buffer-insert-file-contents--default-function
   "Function to use to insert contents when reverting this buffer.
 Gets two args, first the nominal file name to use,
 and second, t if reading the auto-save file.
 
 The function you specify is responsible for updating (or preserving) point.")
 
-(defvar buffer-stale-function nil
+(defun buffer-stale--default-function (&optional _noconfirm)
+  (and buffer-file-name
+       (file-readable-p buffer-file-name)
+       (not (verify-visited-file-modtime (current-buffer)))))
+
+(defvar buffer-stale-function #'buffer-stale--default-function
   "Function to check whether a non-file buffer needs reverting.
 This should be a function with one optional argument NOCONFIRM.
 Auto Revert Mode passes t for NOCONFIRM.  The function should return
@@ -5277,6 +5377,11 @@ This is true even if a `revert-buffer-function' is being used.")
 
 (defvar revert-buffer-internal-hook)
 
+;; `revert-buffer-function' was defined long ago to be a function of only
+;; 2 arguments, so we have to use a dynbind variable to pass the
+;; `preserve-modes' argument of `revert-buffer'.
+(defvar revert-buffer-preserve-modes)
+
 (defun revert-buffer (&optional ignore-auto noconfirm preserve-modes)
   "Replace current buffer text with the text of the visited file on disk.
 This undoes all changes since the file was visited or saved.
@@ -5318,112 +5423,112 @@ non-nil, it is called instead of rereading visited file contents."
   ;; reversal of the argument sense.  So I'm just changing the user
   ;; interface, but leaving the programmatic interface the same.
   (interactive (list (not current-prefix-arg)))
-  (if revert-buffer-function
-      (let ((revert-buffer-in-progress-p t))
-        (funcall revert-buffer-function ignore-auto noconfirm))
-    (with-current-buffer (or (buffer-base-buffer (current-buffer))
-                            (current-buffer))
-      (let* ((revert-buffer-in-progress-p t)
-             (auto-save-p (and (not ignore-auto)
-                              (recent-auto-save-p)
-                              buffer-auto-save-file-name
-                              (file-readable-p buffer-auto-save-file-name)
-                              (y-or-n-p
-     "Buffer has been auto-saved recently.  Revert from auto-save file? ")))
-            (file-name (if auto-save-p
-                           buffer-auto-save-file-name
-                         buffer-file-name)))
-       (cond ((null file-name)
-              (error "Buffer does not seem to be associated with any file"))
-             ((or noconfirm
-                  (and (not (buffer-modified-p))
-                       (catch 'found
-                         (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)))
-              (run-hooks 'before-revert-hook)
-              ;; If file was backed up but has changed since,
-              ;; we should make another backup.
-              (and (not auto-save-p)
-                   (not (verify-visited-file-modtime (current-buffer)))
-                   (setq buffer-backed-up nil))
-              ;; Effectively copy the after-revert-hook status,
-              ;; since after-find-file will clobber it.
-              (let ((global-hook (default-value 'after-revert-hook))
-                    (local-hook (when (local-variable-p 'after-revert-hook)
-                                  after-revert-hook))
-                    (inhibit-read-only t))
-                (cond
-                 (revert-buffer-insert-file-contents-function
-                  (unless (eq buffer-undo-list t)
-                    ;; Get rid of all undo records for this buffer.
-                    (setq buffer-undo-list nil))
-                  ;; Don't make undo records for the reversion.
-                  (let ((buffer-undo-list t))
-                    (funcall revert-buffer-insert-file-contents-function
-                             file-name auto-save-p)))
-                 ((not (file-exists-p file-name))
-                  (error (if buffer-file-number
-                             "File %s no longer exists!"
-                           "Cannot revert nonexistent file %s")
-                         file-name))
-                 ((not (file-readable-p file-name))
-                  (error (if buffer-file-number
-                             "File %s no longer readable!"
-                           "Cannot revert unreadable file %s")
-                         file-name))
-                 (t
-                  ;; Bind buffer-file-name to nil
-                  ;; so that we don't try to lock the file.
-                  (let ((buffer-file-name nil))
-                    (or auto-save-p
-                        (unlock-buffer)))
-                  (widen)
-                  (let ((coding-system-for-read
-                         ;; Auto-saved file should be read by Emacs's
-                         ;; internal coding.
-                         (if auto-save-p 'auto-save-coding
-                           (or coding-system-for-read
-                               (and
-                                buffer-file-coding-system-explicit
-                                (car buffer-file-coding-system-explicit))))))
-                    (if (and (not enable-multibyte-characters)
-                             coding-system-for-read
-                             (not (memq (coding-system-base
-                                         coding-system-for-read)
-                                        '(no-conversion raw-text))))
-                        ;; As a coding system suitable for multibyte
-                        ;; buffer is specified, make the current
-                        ;; buffer multibyte.
-                        (set-buffer-multibyte t))
-
-                    ;; This force after-insert-file-set-coding
-                    ;; (called from insert-file-contents) to set
-                    ;; buffer-file-coding-system to a proper value.
-                    (kill-local-variable 'buffer-file-coding-system)
-
-                    ;; Note that this preserves point in an intelligent way.
-                    (if preserve-modes
-                        (let ((buffer-file-format buffer-file-format))
-                          (insert-file-contents file-name (not auto-save-p)
-                                                nil nil t))
-                      (insert-file-contents file-name (not auto-save-p)
-                                            nil nil t)))))
-                ;; Recompute the truename in case changes in symlinks
-                ;; have changed the truename.
-                (setq buffer-file-truename
-                      (abbreviate-file-name (file-truename buffer-file-name)))
-                (after-find-file nil nil t nil preserve-modes)
-                ;; Run after-revert-hook as it was before we reverted.
-                (setq-default revert-buffer-internal-hook global-hook)
-                (if local-hook
-                    (set (make-local-variable 'revert-buffer-internal-hook)
-                         local-hook)
-                  (kill-local-variable 'revert-buffer-internal-hook))
-                (run-hooks 'revert-buffer-internal-hook))
-              t))))))
+  (let ((revert-buffer-in-progress-p t)
+        (revert-buffer-preserve-modes preserve-modes))
+    (funcall (or revert-buffer-function #'revert-buffer--default)
+             ignore-auto noconfirm)))
+(defun revert-buffer--default (ignore-auto noconfirm)
+  (with-current-buffer (or (buffer-base-buffer (current-buffer))
+                           (current-buffer))
+    (let* ((auto-save-p (and (not ignore-auto)
+                             (recent-auto-save-p)
+                             buffer-auto-save-file-name
+                             (file-readable-p buffer-auto-save-file-name)
+                             (y-or-n-p
+                              "Buffer has been auto-saved recently.  Revert from auto-save file? ")))
+           (file-name (if auto-save-p
+                          buffer-auto-save-file-name
+                        buffer-file-name)))
+      (cond ((null file-name)
+             (error "Buffer does not seem to be associated with any file"))
+            ((or noconfirm
+                 (and (not (buffer-modified-p))
+                      (catch 'found
+                        (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)))
+             (run-hooks 'before-revert-hook)
+             ;; If file was backed up but has changed since,
+             ;; we should make another backup.
+             (and (not auto-save-p)
+                  (not (verify-visited-file-modtime (current-buffer)))
+                  (setq buffer-backed-up nil))
+             ;; Effectively copy the after-revert-hook status,
+             ;; since after-find-file will clobber it.
+             (let ((global-hook (default-value 'after-revert-hook))
+                   (local-hook (when (local-variable-p 'after-revert-hook)
+                                 after-revert-hook))
+                   (inhibit-read-only t))
+               ;; FIXME: Throw away undo-log when preserve-modes is nil?
+               (funcall
+                (or revert-buffer-insert-file-contents-function
+                    #'revert-buffer-insert-file-contents--default-function)
+                file-name auto-save-p)
+               ;; Recompute the truename in case changes in symlinks
+               ;; have changed the truename.
+               (setq buffer-file-truename
+                     (abbreviate-file-name (file-truename buffer-file-name)))
+               (after-find-file nil nil t nil revert-buffer-preserve-modes)
+               ;; Run after-revert-hook as it was before we reverted.
+               (setq-default revert-buffer-internal-hook global-hook)
+               (if local-hook
+                   (set (make-local-variable 'revert-buffer-internal-hook)
+                        local-hook)
+                 (kill-local-variable 'revert-buffer-internal-hook))
+               (run-hooks 'revert-buffer-internal-hook))
+             t)))))
+
+(defun revert-buffer-insert-file-contents--default-function (file-name auto-save-p)
+  (cond
+   ((not (file-exists-p file-name))
+    (error (if buffer-file-number
+               "File %s no longer exists!"
+             "Cannot revert nonexistent file %s")
+           file-name))
+   ((not (file-readable-p file-name))
+    (error (if buffer-file-number
+               "File %s no longer readable!"
+             "Cannot revert unreadable file %s")
+           file-name))
+   (t
+    ;; Bind buffer-file-name to nil
+    ;; so that we don't try to lock the file.
+    (let ((buffer-file-name nil))
+      (or auto-save-p
+          (unlock-buffer)))
+    (widen)
+    (let ((coding-system-for-read
+           ;; Auto-saved file should be read by Emacs's
+           ;; internal coding.
+           (if auto-save-p 'auto-save-coding
+             (or coding-system-for-read
+                 (and
+                  buffer-file-coding-system-explicit
+                  (car buffer-file-coding-system-explicit))))))
+      (if (and (not enable-multibyte-characters)
+               coding-system-for-read
+               (not (memq (coding-system-base
+                           coding-system-for-read)
+                          '(no-conversion raw-text))))
+          ;; As a coding system suitable for multibyte
+          ;; buffer is specified, make the current
+          ;; buffer multibyte.
+          (set-buffer-multibyte t))
+
+      ;; This force after-insert-file-set-coding
+      ;; (called from insert-file-contents) to set
+      ;; buffer-file-coding-system to a proper value.
+      (kill-local-variable 'buffer-file-coding-system)
+
+      ;; Note that this preserves point in an intelligent way.
+      (if revert-buffer-preserve-modes
+          (let ((buffer-file-format buffer-file-format))
+            (insert-file-contents file-name (not auto-save-p)
+                                  nil nil t))
+        (insert-file-contents file-name (not auto-save-p)
+                              nil nil t))))))
 
 (defun recover-this-file ()
   "Recover the visited file--get contents from its last auto-save file."
@@ -5476,7 +5581,7 @@ non-nil, it is called instead of rereading visited file contents."
             (insert-file-contents file-name nil)
             (set-buffer-file-coding-system coding-system))
           (after-find-file nil nil t))
-         (t (user-error "Recover-file cancelled")))))
+         (t (user-error "Recover-file canceled")))))
 
 (defun recover-session ()
   "Recover auto save files from a previous Emacs session.
@@ -6177,9 +6282,10 @@ normally equivalent short `-D' option is just passed on to
                    ;; directory if FILE is a symbolic link.
                    (unless full-directory-p
                      (setq switches
-                           (if (stringp switches)
-                               (concat switches " -d")
-                             (add-to-list 'switches "-d" 'append))))
+                           (cond
+                             ((stringp switches) (concat switches " -d"))
+                             ((member "-d" switches) switches)
+                             (t (append switches '("-d"))))))
                    (apply 'call-process
                           insert-directory-program nil t nil
                           (append
@@ -6397,10 +6503,11 @@ the low level primitive, does not.  See also `kill-emacs-hook'.")
 (defcustom confirm-kill-emacs nil
   "How to ask for confirmation when leaving Emacs.
 If nil, the default, don't ask at all.  If the value is non-nil, it should
-be a predicate function such as `yes-or-no-p'."
+be a predicate function; for example `yes-or-no-p'."
   :type '(choice (const :tag "Ask with yes-or-no-p" yes-or-no-p)
                 (const :tag "Ask with y-or-n-p" y-or-n-p)
-                (const :tag "Don't confirm" nil))
+                (const :tag "Don't confirm" nil)
+                (function :tag "Predicate function"))
   :group 'convenience
   :version "21.1")
 
@@ -6428,7 +6535,7 @@ if any returns nil.  If `confirm-kill-emacs' is non-nil, calls it."
                    (setq active t))
               (setq processes (cdr processes)))
             (or (not active)
-                (with-temp-buffer-window
+                (with-current-buffer-window
                  (get-buffer-create "*Process List*") nil
                  #'(lambda (window _value)
                      (with-selected-window window
@@ -6452,7 +6559,7 @@ With prefix ARG, silently save all file-visiting buffers, then kill.
 If emacsclient was started with a list of filenames to edit, then
 only these files will be asked to be saved."
   (interactive "P")
-  (if (frame-parameter (selected-frame) 'client)
+  (if (frame-parameter nil 'client)
       (server-save-buffers-kill-terminal arg)
     (save-buffers-kill-emacs arg)))
 \f
@@ -6653,7 +6760,9 @@ based on existing mode bits, as in \"og+rX-w\"."
          (string-to-number value 8)
        (file-modes-symbolic-to-number value modes)))))
 
-\f
+(define-obsolete-variable-alias 'cache-long-line-scans
+  'cache-long-scans "24.4")
+
 ;; Trashcan handling.
 (defcustom trash-directory nil
   "Directory for `move-file-to-trash' to move files and directories to.