]> code.delx.au - gnu-emacs/blobdiff - lisp/files.el
Replace lisp-indent-hook with lisp-indent-function throughout.
[gnu-emacs] / lisp / files.el
index e80e8fc766b580bd5a2609977ba69fee011ee2e1..a4bb4f86d4e9b6e6ec7cc8cf2426daac258bfc9b 100644 (file)
@@ -1,7 +1,7 @@
 ;;; files.el --- file input and output commands for Emacs
 
-;; Copyright (C) 1985,86,87,92,93,94,95,96,97,98,99,2000,01,02,03,2004
-;;  Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+;;   1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 
@@ -273,14 +273,40 @@ Includes the new backup.  Must be > 0"
   :group 'backup)
 
 (defcustom require-final-newline nil
-  "*Value of t says silently ensure a file ends in a newline when it is saved.
-Non-nil but not t says ask user whether to add a newline when there isn't one.
-nil means don't add newlines."
-  :type '(choice (const :tag "Off" nil)
-                (const :tag "Add" t)
+  "*Whether to add a newline automatically at the end of the file.
+
+A value of t means do this only when the file is about to be saved.
+A value of `visit' means do this right after the file is visited.
+A value of `visit-save' means do it at both of those times.
+Any other non-nil value means ask user whether to add a newline, when saving.
+nil means don't add newlines.
+
+Certain major modes set this locally to the value obtained
+from `mode-require-final-newline'."
+  :type '(choice (const :tag "When visiting" visit)
+                (const :tag "When saving" t)
+                (const :tag "When visiting or saving" visit-save)
+                (const :tag "Never" nil)
                 (other :tag "Ask" ask))
   :group 'editing-basics)
 
+(defcustom mode-require-final-newline t
+  "*Whether to add a newline at the end of the file, in certain major modes.
+Those modes set `require-final-newline' to this value when you enable them.
+They do so because they are used for files that are supposed
+to end in newlines, and the question is how to arrange that.
+
+A value of t means do this only when the file is about to be saved.
+A value of `visit' means do this right after the file is visited.
+A value of `visit-save' means do it at both of those times.
+Any other non-nil value means ask user whether to add a newline, when saving."
+  :type '(choice (const :tag "When visiting" visit)
+                (const :tag "When saving" t)
+                (const :tag "When visiting or saving" visit-save)
+                (other :tag "Ask" ask))
+  :group 'editing-basics
+  :version "22.1")
+
 (defcustom auto-save-default t
   "*Non-nil says by default do auto-saving of every file-visiting buffer."
   :type 'boolean
@@ -351,7 +377,7 @@ Variable `buffer-file-name' is already set up.
 The functions are called in the order given until one of them returns non-nil.")
 (defvaralias 'find-file-not-found-hooks 'find-file-not-found-functions)
 (make-obsolete-variable
- 'find-file-not-found-hooks 'find-file-not-found-functions "21.4")
+ 'find-file-not-found-hooks 'find-file-not-found-functions "22.1")
 
 ;;;It is not useful to make this a local variable.
 ;;;(put 'find-file-hooks 'permanent-local t)
@@ -362,9 +388,9 @@ functions are called."
   :group 'find-file
   :type 'hook
   :options '(auto-insert)
-  :version "21.4")
+  :version "22.1")
 (defvaralias 'find-file-hooks 'find-file-hook)
-(make-obsolete-variable 'find-file-hooks 'find-file-hook "21.4")
+(make-obsolete-variable 'find-file-hooks 'find-file-hook "22.1")
 
 (defvar write-file-functions nil
   "List of functions to be called before writing out a buffer to a file.
@@ -383,12 +409,12 @@ node `(elisp)Saving Buffers'.)  To perform various checks or
 updates before the buffer is saved, use `before-save-hook' .")
 (put 'write-file-functions 'permanent-local t)
 (defvaralias 'write-file-hooks 'write-file-functions)
-(make-obsolete-variable 'write-file-hooks 'write-file-functions "21.4")
+(make-obsolete-variable 'write-file-hooks 'write-file-functions "22.1")
 
 (defvar local-write-file-hooks nil)
 (make-variable-buffer-local 'local-write-file-hooks)
 (put 'local-write-file-hooks 'permanent-local t)
-(make-obsolete-variable 'local-write-file-hooks 'write-file-functions "21.4")
+(make-obsolete-variable 'local-write-file-hooks 'write-file-functions "22.1")
 
 (defvar write-contents-functions nil
   "List of functions to be called before writing out a buffer to a file.
@@ -408,7 +434,7 @@ To perform various checks or updates before the buffer is saved,
 use `before-save-hook'.")
 (make-variable-buffer-local 'write-contents-functions)
 (defvaralias 'write-contents-hooks 'write-contents-functions)
-(make-obsolete-variable 'write-contents-hooks 'write-contents-functions "21.4")
+(make-obsolete-variable 'write-contents-hooks 'write-contents-functions "22.1")
 
 (defcustom enable-local-variables t
   "*Control use of local variables in files you visit.
@@ -932,8 +958,7 @@ suppress wildcard expansion by setting `find-file-wildcards'.
 
 To visit a file without any kind of conversion and without
 automatically choosing a major mode, use \\[find-file-literally]."
-  (interactive
-   (find-file-read-args "Find file: " nil))
+  (interactive (find-file-read-args "Find file: " nil))
   (let ((value (find-file-noselect filename nil nil wildcards)))
     (if (listp value)
        (mapcar 'switch-to-buffer (nreverse value))
@@ -955,8 +980,8 @@ expand wildcards (if any) and visit multiple files."
     (if (listp value)
        (progn
          (setq value (nreverse value))
-         (switch-to-buffer-other-window (car value))
-         (mapcar 'switch-to-buffer (cdr value)))
+         (cons (switch-to-buffer-other-window (car value))
+               (mapcar 'switch-to-buffer (cdr value))))
       (switch-to-buffer-other-window value))))
 
 (defun find-file-other-frame (filename &optional wildcards)
@@ -975,8 +1000,8 @@ expand wildcards (if any) and visit multiple files."
     (if (listp value)
        (progn
          (setq value (nreverse value))
-         (switch-to-buffer-other-frame (car value))
-         (mapcar 'switch-to-buffer (cdr value)))
+         (cons (switch-to-buffer-other-frame (car value))
+               (mapcar 'switch-to-buffer (cdr value))))
       (switch-to-buffer-other-frame value))))
 
 (defun find-file-existing (filename &optional wildcards)
@@ -991,35 +1016,53 @@ Like \\[find-file] but only allow files that exists."
   "Edit file FILENAME but don't allow changes.
 Like \\[find-file] but marks buffer as read-only.
 Use \\[toggle-read-only] to permit editing."
-  (interactive (find-file-read-args "Find file read-only: " t))
-  (unless (file-exists-p filename) (error "%s does not exist" filename))
-  (find-file filename wildcards)
-  (toggle-read-only 1)
-  (current-buffer))
+  (interactive (find-file-read-args "Find file read-only: " nil))
+  (unless (or (and wildcards find-file-wildcards
+                  (not (string-match "\\`/:" filename))
+                  (string-match "[[*?]" filename))
+             (file-exists-p filename))
+    (error "%s does not exist" filename))
+  (let ((value (find-file filename wildcards)))
+    (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
+         (if (listp value) value (list value)))
+    value))
 
 (defun find-file-read-only-other-window (filename &optional wildcards)
   "Edit file FILENAME in another window but don't allow changes.
 Like \\[find-file-other-window] but marks buffer as read-only.
 Use \\[toggle-read-only] to permit editing."
-  (interactive (find-file-read-args "Find file read-only other window: " t))
-  (unless (file-exists-p filename) (error "%s does not exist" filename))
-  (find-file-other-window filename wildcards)
-  (toggle-read-only 1)
-  (current-buffer))
+  (interactive (find-file-read-args "Find file read-only other window: " nil))
+  (unless (or (and wildcards find-file-wildcards
+                  (not (string-match "\\`/:" filename))
+                  (string-match "[[*?]" filename))
+             (file-exists-p filename))
+    (error "%s does not exist" filename))
+  (let ((value (find-file-other-window filename wildcards)))
+    (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
+         (if (listp value) value (list value)))
+    value))
 
 (defun find-file-read-only-other-frame (filename &optional wildcards)
   "Edit file FILENAME in another frame but don't allow changes.
 Like \\[find-file-other-frame] but marks buffer as read-only.
 Use \\[toggle-read-only] to permit editing."
-  (interactive (find-file-read-args "Find file read-only other frame: " t))
-  (unless (file-exists-p filename) (error "%s does not exist" filename))
-  (find-file-other-frame filename wildcards)
-  (toggle-read-only 1)
-  (current-buffer))
-
-(defun find-alternate-file-other-window (filename)
+  (interactive (find-file-read-args "Find file read-only other frame: " nil))
+  (unless (or (and wildcards find-file-wildcards
+                  (not (string-match "\\`/:" filename))
+                  (string-match "[[*?]" filename))
+             (file-exists-p filename))
+    (error "%s does not exist" filename))
+  (let ((value (find-file-other-frame filename wildcards)))
+    (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
+         (if (listp value) value (list value)))
+    value))
+
+(defun find-alternate-file-other-window (filename &optional wildcards)
   "Find file FILENAME as a replacement for the file in the next window.
-This command does not select that window."
+This command does not select that window.
+
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and replace the file with multiple files."
   (interactive
    (save-selected-window
      (other-window 1)
@@ -1030,17 +1073,21 @@ This command does not select that window."
            (setq file-name (file-name-nondirectory file)
                  file-dir (file-name-directory file)))
        (list (read-file-name
-             "Find alternate file: " file-dir nil nil file-name)))))
+             "Find alternate file: " file-dir nil nil file-name)
+            t))))
   (if (one-window-p)
-      (find-file-other-window filename)
+      (find-file-other-window filename wildcards)
     (save-selected-window
       (other-window 1)
-      (find-alternate-file filename))))
+      (find-alternate-file filename wildcards))))
 
-(defun find-alternate-file (filename)
+(defun find-alternate-file (filename &optional wildcards)
   "Find file FILENAME, select its buffer, kill previous buffer.
 If the current buffer now contains an empty file that you just visited
-\(presumably by mistake), use this command to visit the file you really want."
+\(presumably by mistake), use this command to visit the file you really want.
+
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and replace the file with multiple files."
   (interactive
    (let ((file buffer-file-name)
         (file-name nil)
@@ -1049,7 +1096,8 @@ If the current buffer now contains an empty file that you just visited
          (setq file-name (file-name-nondirectory file)
                file-dir (file-name-directory file)))
      (list (read-file-name
-           "Find alternate file: " file-dir nil nil file-name))))
+           "Find alternate file: " file-dir nil nil file-name)
+          t)))
   (unless (run-hook-with-args-until-failure 'kill-buffer-query-functions)
     (error "Aborted"))
   (when (and (buffer-modified-p) (buffer-file-name))
@@ -1077,7 +1125,7 @@ If the current buffer now contains an empty file that you just visited
          (setq buffer-file-truename nil)
          ;; Likewise for dired buffers.
          (setq dired-directory nil)
-         (find-file filename))
+         (find-file filename wildcards))
       (when (eq obuf (current-buffer))
        ;; This executes if find-file gets an error
        ;; and does not really find anything.
@@ -1178,7 +1226,8 @@ name to this list as a string."
   "Return the buffer visiting file FILENAME (a string).
 This is like `get-file-buffer', except that it checks for any buffer
 visiting the same file, possibly under a different name.
-If PREDICATE is non-nil, only a buffer satisfying it can be returned.
+If PREDICATE is non-nil, only buffers satisfying it are eligible,
+and others are ignored.
 If there is no such live buffer, return nil."
   (let ((predicate (or predicate #'identity))
         (truename (abbreviate-file-name (file-truename filename))))
@@ -1235,7 +1284,7 @@ suppresses this warning."
 When nil, never request confirmation."
   :group 'files
   :group 'find-file
-  :version "21.4"
+  :version "22.1"
   :type '(choice integer (const :tag "Never request confirmation" nil)))
 
 (defun find-file-noselect (filename &optional nowarn rawfile wildcards)
@@ -1247,8 +1296,8 @@ Optional first arg NOWARN non-nil means suppress any warning messages.
 Optional second arg RAWFILE non-nil means the file is read literally.
 Optional third arg WILDCARDS non-nil means do wildcard processing
 and visit all the matching files.  When wildcards are actually
-used and expanded, the value is a list of buffers
-that are visiting the various files."
+used and expanded, return a list of buffers that are visiting
+the various files."
   (setq filename
        (abbreviate-file-name
         (expand-file-name filename)))
@@ -1604,6 +1653,15 @@ unless NOMODES is non-nil."
     (when (and view-read-only view-mode)
       (view-mode-disable))
     (normal-mode t)
+    ;; If requested, add a newline at the end of the file.
+    (and (memq require-final-newline '(visit visit-save))
+        (> (point-max) (point-min))
+        (/= (char-after (1- (point-max))) ?\n)
+        (not (and (eq selective-display t)
+                  (= (char-after (1- (point-max))) ?\r)))
+        (save-excursion
+          (goto-char (point-max))
+          (insert "\n")))
     (when (and buffer-read-only
               view-read-only
               (not (eq (get major-mode 'mode-class) 'special)))
@@ -1798,8 +1856,14 @@ mode function to use.  FUNCTION will be called, unless it is nil.
 
 If the element has the form (REGEXP FUNCTION NON-NIL), then after
 calling FUNCTION (if it's not nil), we delete the suffix that matched
-REGEXP and search the list again for another match.")
+REGEXP and search the list again for another match.
+
+If the file name matches `inhibit-first-line-modes-regexps',
+then `auto-mode-alist' is not processed.
 
+See also `interpreter-mode-alist', which detects executable script modes
+based on the interpreters they specify to run,
+and `magic-mode-alist', which determines modes based on file contents.")
 
 (defvar interpreter-mode-alist
   ;; Note: The entries for the modes defined in cc-mode.el (awk-mode
@@ -1844,11 +1908,13 @@ REGEXP and search the list again for another match.")
      ("guile" . scheme-mode)
      ("clisp" . lisp-mode)))
   "Alist mapping interpreter names to major modes.
-This alist applies to files whose first line starts with `#!'.
+This is used for files whose first lines match `auto-mode-interpreter-regexp'.
 Each element looks like (INTERPRETER . MODE).
 The car of each element is compared with
 the name of the interpreter specified in the first line.
-If it matches, mode MODE is selected.")
+If it matches, mode MODE is selected.
+
+See also `auto-mode-alist'.")
 
 (defvar inhibit-first-line-modes-regexps '("\\.tar\\'" "\\.tgz\\'")
   "List of regexps; if one matches a file name, don't look for `-*-'.")
@@ -1877,12 +1943,14 @@ with that interpreter in `interpreter-mode-alist'.")
        (concat "\\(?:<\\?xml\\s +[^>]*>\\)?\\s *<"
                comment-re "*"
                "\\(?:!DOCTYPE\\s +[^>]*>\\s *<\\s *" comment-re "*\\)?"
-               "[Hh][Tt][Mm][Ll]")) . html-mode)
+               "[Hh][Tt][Mm][Ll]"))
+     . html-mode)
     ;; These two must come after html, because they are more general:
     ("<\\?xml " . xml-mode)
     (,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
             (comment-re (concat "\\(?:!--" incomment-re "*-->\\s *<\\)")))
-       (concat "\\s *<" comment-re "*!DOCTYPE ")) . sgml-mode)
+       (concat "\\s *<" comment-re "*!DOCTYPE "))
+     . sgml-mode)
     ("%![^V]" . ps-mode)
     ("# xmcd " . conf-unix-mode))
   "Alist of buffer beginnings vs. corresponding major mode functions.
@@ -2144,94 +2212,86 @@ is specified, returning t if it is specified."
     (save-excursion
       (goto-char (point-max))
       (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
-      (if (let ((case-fold-search t))
-           (and (search-forward "Local Variables:" nil t)
-                (or (eq enable-local-variables t)
-                    mode-only
-                    (and enable-local-variables
-                         (save-window-excursion
-                           (switch-to-buffer (current-buffer))
-                           (save-excursion
-                             (beginning-of-line)
-                             (set-window-start (selected-window) (point)))
-                           (y-or-n-p (format "Set local variables as specified at end of %s? "
-                                             (if buffer-file-name
-                                                 (file-name-nondirectory
-                                                  buffer-file-name)
-                                               (concat "buffer "
-                                                       (buffer-name))))))))))
-         (let (prefix prefixlen suffix beg
-               (enable-local-eval enable-local-eval))
-           ;; The prefix is what comes before "local variables:" in its line.
-           ;; The suffix is what comes after "local variables:" in its line.
-           (skip-chars-forward " \t")
-           (or (eolp)
-               (setq suffix (buffer-substring (point)
-                                              (progn (end-of-line) (point)))))
-           (goto-char (match-beginning 0))
-           (or (bolp)
-               (setq prefix
-                     (buffer-substring (point)
-                                       (progn (beginning-of-line) (point)))))
-
-           (if prefix (setq prefixlen (length prefix)
-                            prefix (regexp-quote prefix)))
-           (if suffix (setq suffix (concat (regexp-quote suffix) "$")))
-           (forward-line 1)
-           (let ((startpos (point))
-                 endpos
-                 (thisbuf (current-buffer)))
-             (save-excursion
-               (if (not (re-search-forward
-                         (concat (or prefix "")
-                                 "[ \t]*End:[ \t]*"
-                                 (or suffix ""))
-                         nil t))
-                   (error "Local variables list is not properly terminated"))
-               (beginning-of-line)
-               (setq endpos (point)))
-
-             (with-temp-buffer
-               (insert-buffer-substring thisbuf startpos endpos)
-               (goto-char (point-min))
-               (subst-char-in-region (point) (point-max)
-                                     ?\^m ?\n)
-               (while (not (eobp))
-                 ;; Discard the prefix, if any.
-                 (if prefix
-                     (if (looking-at prefix)
-                         (delete-region (point) (match-end 0))
-                       (error "Local variables entry is missing the prefix")))
-                 (end-of-line)
-                 ;; Discard the suffix, if any.
-                 (if suffix
-                     (if (looking-back suffix)
-                         (delete-region (match-beginning 0) (point))
-                       (error "Local variables entry is missing the suffix")))
-                 (forward-line 1))
-               (goto-char (point-min))
-
-               (while (not (eobp))
-                 ;; 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 (read str))
-                        val)
-                   ;; Read the variable value.
-                   (skip-chars-forward "^:")
-                   (forward-char 1)
-                   (setq val (read (current-buffer)))
-                   (if mode-only
-                       (if (eq var 'mode)
-                           (setq mode-specified t))
-                     ;; Set the variable.  "Variables" mode and eval are funny.
-                     (with-current-buffer thisbuf
-                       (hack-one-local-variable var val))))
-                 (forward-line 1)))))))
+      (when (let ((case-fold-search t))
+             (and (search-forward "Local Variables:" nil t)
+                  (or (eq enable-local-variables t)
+                      mode-only
+                      (and enable-local-variables
+                           (save-window-excursion
+                             (switch-to-buffer (current-buffer))
+                             (save-excursion
+                               (beginning-of-line)
+                               (set-window-start (selected-window) (point)))
+                             (y-or-n-p (format "Set local variables as specified at end of %s? "
+                                               (if buffer-file-name
+                                                   (file-name-nondirectory
+                                                    buffer-file-name)
+                                                 (concat "buffer "
+                                                         (buffer-name))))))))))
+       (skip-chars-forward " \t")
+       (let ((enable-local-eval enable-local-eval)
+             ;; suffix is what comes after "local variables:" in its line.
+             (suffix
+              (concat
+               (regexp-quote (buffer-substring (point) (line-end-position)))
+               "$"))
+             ;; prefix is what comes before "local variables:" in its line.
+             (prefix
+              (concat "^" (regexp-quote
+                           (buffer-substring (line-beginning-position)
+                                             (match-beginning 0)))))
+             beg)
+
+         (forward-line 1)
+         (let ((startpos (point))
+               endpos
+               (thisbuf (current-buffer)))
+           (save-excursion
+             (if (not (re-search-forward
+                       (concat prefix "[ \t]*End:[ \t]*" suffix)
+                       nil t))
+                 (error "Local variables list is not properly terminated"))
+             (beginning-of-line)
+             (setq endpos (point)))
+
+           (with-temp-buffer
+             (insert-buffer-substring thisbuf startpos endpos)
+             (goto-char (point-min))
+             (subst-char-in-region (point) (point-max) ?\^m ?\n)
+             (while (not (eobp))
+               ;; Discard the prefix.
+               (if (looking-at prefix)
+                   (delete-region (point) (match-end 0))
+                 (error "Local variables entry is missing the prefix"))
+               (end-of-line)
+               ;; Discard the suffix.
+               (if (looking-back suffix)
+                   (delete-region (match-beginning 0) (point))
+                 (error "Local variables entry is missing the suffix"))
+               (forward-line 1))
+             (goto-char (point-min))
+
+             (while (not (eobp))
+               ;; 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 (read str))
+                      val)
+                 ;; Read the variable value.
+                 (skip-chars-forward "^:")
+                 (forward-char 1)
+                 (setq val (read (current-buffer)))
+                 (if mode-only
+                     (if (eq var 'mode)
+                         (setq mode-specified t))
+                   ;; Set the variable.  "Variables" mode and eval are funny.
+                   (with-current-buffer thisbuf
+                     (hack-one-local-variable var val))))
+               (forward-line 1)))))))
     (unless mode-only
       (run-hooks 'hack-local-variables-hook))
     mode-specified))
@@ -2318,7 +2378,7 @@ Add expressions to this list if you want Emacs to evaluate them, when
 they appear in an `eval' local variable specification, without first
 asking you for confirmation."
   :group 'find-file
-  :version "21.4"
+  :version "22.1"
   :type '(repeat sexp))
 
 (put 'c-set-style 'safe-local-eval-function t)
@@ -2784,13 +2844,18 @@ ignored."
 
 (defun normal-backup-enable-predicate (name)
   "Default `backup-enable-predicate' function.
-Checks for files in `temporary-file-directory' or
-`small-temporary-file-directory'."
+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
@@ -3172,6 +3237,7 @@ Before and after saving the buffer, this function runs
                   (not (and (eq selective-display t)
                             (= (char-after (1- (point-max))) ?\r)))
                   (or (eq require-final-newline t)
+                      (eq require-final-newline 'visit-save)
                       (and require-final-newline
                            (y-or-n-p
                             (format "Buffer %s does not end in newline.  Add one? "
@@ -3213,10 +3279,12 @@ Before and after saving the buffer, this function runs
 ;; but inhibited if one of write-file-functions returns non-nil.
 ;; It returns a value (MODES . BACKUPNAME), like backup-buffer.
 (defun basic-save-buffer-1 ()
-  (if save-buffer-coding-system
-      (let ((coding-system-for-write save-buffer-coding-system))
+  (prog1
+      (if save-buffer-coding-system
+         (let ((coding-system-for-write save-buffer-coding-system))
+           (basic-save-buffer-2))
        (basic-save-buffer-2))
-    (basic-save-buffer-2)))
+    (setq buffer-file-coding-system-explicit last-coding-system-used)))
 
 ;; This returns a value (MODES . BACKUPNAME), like backup-buffer.
 (defun basic-save-buffer-2 ()
@@ -3341,6 +3409,10 @@ This requires the external program `diff' to be in your `exec-path'."
   "ACTION-ALIST argument used in call to `map-y-or-n-p'.")
 (put 'save-some-buffers-action-alist 'risky-local-variable t)
 
+(defvar buffer-save-without-query nil
+  "Non-nil means `save-some-buffers' should save this buffer without asking.")
+(make-variable-buffer-local 'buffer-save-without-query)
+
 (defun save-some-buffers (&optional arg pred)
   "Save some modified file-visiting buffers.  Asks user about each one.
 You can answer `y' to save, `n' not to save, `C-r' to look at the
@@ -3358,8 +3430,18 @@ See `save-some-buffers-action-alist' if you want to
 change the additional actions you can take on files."
   (interactive "P")
   (save-window-excursion
-    (let* ((queried nil)
-          (files-done
+    (let* (queried some-automatic
+          files-done abbrevs-done)
+      (dolist (buffer (buffer-list))
+       ;; First save any buffers that we're supposed to save unconditionally.
+       ;; That way the following code won't ask about them.
+       (with-current-buffer buffer
+         (when (and buffer-save-without-query (buffer-modified-p))
+           (setq some-automatic t)
+           (save-buffer))))
+      ;; Ask about those buffers that merit it,
+      ;; and record the number thus saved.
+      (setq files-done
            (map-y-or-n-p
             (function
              (lambda (buffer)
@@ -3388,19 +3470,22 @@ change the additional actions you can take on files."
             (buffer-list)
             '("buffer" "buffers" "save")
             save-some-buffers-action-alist))
-          (abbrevs-done
-           (and save-abbrevs abbrevs-changed
-                (progn
-                  (if (or arg
-                          (eq save-abbrevs 'silently)
-                          (y-or-n-p (format "Save abbrevs in %s? "
-                                            abbrev-file-name)))
-                      (write-abbrev-file nil))
-                  ;; Don't keep bothering user if he says no.
-                  (setq abbrevs-changed nil)
-                  t))))
+      ;; Maybe to save abbrevs, and record whether
+      ;; we either saved them or asked to.
+      (and save-abbrevs abbrevs-changed
+          (progn
+            (if (or arg
+                    (eq save-abbrevs 'silently)
+                    (y-or-n-p (format "Save abbrevs in %s? "
+                                      abbrev-file-name)))
+                (write-abbrev-file nil))
+            ;; Don't keep bothering user if he says no.
+            (setq abbrevs-changed nil)
+            (setq abbrevs-done t)))
       (or queried (> files-done 0) abbrevs-done
-         (message "(No files need saving)")))))
+         (message (if some-automatic
+                      "(Some special files were saved without asking)"
+                    "(No files need saving)"))))))
 \f
 (defun not-modified (&optional arg)
   "Mark current buffer as unmodified, not needing to be saved.
@@ -3669,11 +3754,11 @@ non-nil, it is called instead of rereading visited file contents."
                         (unlock-buffer)))
                   (widen)
                   (let ((coding-system-for-read
-                         ;; Auto-saved file shoule be read without
-                         ;; any code conversion.
-                         (if auto-save-p 'emacs-mule-unix
+                         ;; Auto-saved file shoule be read by Emacs'
+                         ;; internal coding.
+                         (if auto-save-p 'auto-save-coding
                            (or coding-system-for-read
-                               buffer-file-coding-system))))
+                               buffer-file-coding-system-explicit))))
                     ;; This force after-insert-file-set-coding
                     ;; (called from insert-file-contents) to set
                     ;; buffer-file-coding-system to a proper value.
@@ -4287,6 +4372,8 @@ program specified by `directory-free-space-program' if that is non-nil."
                  (buffer-substring (point) end)))))))))
 
 
+(defvar insert-directory-ls-version 'unknown)
+
 ;; insert-directory
 ;; - must insert _exactly_one_line_ describing FILE if WILDCARD and
 ;;   FULL-DIRECTORY-P is nil.
@@ -4396,6 +4483,56 @@ normally equivalent short `-D' option is just passed on to
                                   (concat (file-name-as-directory file) ".")
                                 file))))))))
 
+         ;; If we got "//DIRED//" in the output, it means we got a real
+         ;; directory listing, even if `ls' returned nonzero.
+         ;; So ignore any errors.
+         (when (if (stringp switches)
+                   (string-match "--dired\\>" switches)
+                 (member "--dired" switches))
+           (save-excursion
+             (forward-line -2)
+             (when (looking-at "//SUBDIRED//")
+               (forward-line -1))
+             (if (looking-at "//DIRED//")
+                 (setq result 0))))
+
+         (when (and (not (eq 0 result))
+                    (eq insert-directory-ls-version 'unknown))
+           ;; The first time ls returns an error,
+           ;; find the version numbers of ls,
+           ;; and set insert-directory-ls-version
+           ;; to > if it is more than 5.2.1, < if it is less, nil if it
+           ;; is equal or if the info cannot be obtained.
+           ;; (That can mean it isn't GNU ls.)
+           (let ((version-out
+                  (with-temp-buffer
+                    (call-process "ls" nil t nil "--version")
+                    (buffer-string))))
+             (if (string-match "ls (.*utils) \\([0-9.]*\\)$" version-out)
+                 (let* ((version (match-string 1 version-out))
+                        (split (split-string version "[.]"))
+                        (numbers (mapcar 'string-to-int split))
+                        (min '(5 2 1))
+                        comparison)
+                   (while (and (not comparison) (or numbers min))
+                     (cond ((null min)
+                            (setq comparison '>))
+                           ((null numbers)
+                            (setq comparison '<))
+                           ((> (car numbers) (car min))
+                            (setq comparison '>))
+                           ((< (car numbers) (car min))
+                            (setq comparison '<))
+                           (t
+                            (setq numbers (cdr numbers)
+                                  min (cdr min)))))
+                   (setq insert-directory-ls-version (or comparison '=)))
+               (setq insert-directory-ls-version nil))))
+
+         ;; For GNU ls versions 5.2.2 and up, ignore minor errors.
+         (when (and (eq 1 result) (eq insert-directory-ls-version '>))
+           (setq result 0))
+
          ;; If `insert-directory-program' failed, signal an error.
          (unless (eq 0 result)
            ;; Delete the error message it may have output.
@@ -4418,17 +4555,38 @@ normally equivalent short `-D' option is just passed on to
          (when (if (stringp switches)
                    (string-match "--dired\\>" switches)
                  (member "--dired" switches))
+           ;; The following overshoots by one line for an empty
+           ;; directory listed with "--dired", but without "-a"
+           ;; switch, where the ls output contains a
+           ;; "//DIRED-OPTIONS//" line, but no "//DIRED//" line.
+           ;; We take care of that case later.
            (forward-line -2)
             (when (looking-at "//SUBDIRED//")
               (delete-region (point) (progn (forward-line 1) (point)))
               (forward-line -1))
            (if (looking-at "//DIRED//")
-               (let ((end (line-end-position)))
+               (let ((end (line-end-position))
+                     (linebeg (point))
+                     error-lines)
+                 ;; Find all the lines that are error messages,
+                 ;; and record the bounds of each one.
+                 (goto-char beg)
+                 (while (< (point) linebeg)
+                   (or (eql (following-char) ?\s)
+                       (push (list (point) (line-end-position)) error-lines))
+                   (forward-line 1))
+                 (setq error-lines (nreverse error-lines))
+                 ;; Now read the numeric positions of file names.
+                 (goto-char linebeg)
                  (forward-word 1)
                  (forward-char 3)
                  (while (< (point) end)
-                   (let ((start (+ beg (read (current-buffer))))
-                         (end (+ beg (read (current-buffer)))))
+                   (let ((start (insert-directory-adj-pos
+                                 (+ beg (read (current-buffer)))
+                                 error-lines))
+                         (end (insert-directory-adj-pos
+                               (+ beg (read (current-buffer)))
+                               error-lines)))
                      (if (memq (char-after end) '(?\n ?\ ))
                          ;; End is followed by \n or by " -> ".
                          (put-text-property start end 'dired-filename t)
@@ -4438,11 +4596,13 @@ normally equivalent short `-D' option is just passed on to
                        (end-of-line))))
                  (goto-char end)
                  (beginning-of-line)
-                 (delete-region (point) (progn (forward-line 2) (point))))
-             (forward-line 1)
-             (if (looking-at "//DIRED-OPTIONS//")
-                 (delete-region (point) (progn (forward-line 1) (point)))
-               (forward-line 1))))
+                 (delete-region (point) (progn (forward-line 1) (point))))
+             ;; Take care of the case where the ls output contains a
+             ;; "//DIRED-OPTIONS//"-line, but no "//DIRED//"-line
+             ;; and we went one line too far back (see above).
+             (forward-line 1))
+           (if (looking-at "//DIRED-OPTIONS//")
+               (delete-region (point) (progn (forward-line 1) (point)))))
 
          ;; Now decode what read if necessary.
          (let ((coding (or coding-system-for-read
@@ -4490,6 +4650,18 @@ normally equivalent short `-D' option is just passed on to
                      (end-of-line)
                      (insert " available " available)))))))))))
 
+(defun insert-directory-adj-pos (pos error-lines)
+  "Convert `ls --dired' file name position value POS to a buffer position.
+File name position values returned in ls --dired output
+count only stdout; they don't count the error messages sent to stderr.
+So this function converts to them to real buffer positions.
+ERROR-LINES is a list of buffer positions of error message lines,
+of the form (START END)."
+  (while (and error-lines (< (caar error-lines) pos))
+    (setq pos (+ pos (- (nth 1 (car error-lines)) (nth 0 (car error-lines)))))
+    (pop error-lines))
+  pos)
+
 (defun insert-directory-safely (file switches
                                     &optional wildcard full-directory-p)
   "Insert directory listing for FILE, formatted according to SWITCHES.