(Qcenter): New variable.
[bpt/emacs.git] / lisp / files.el
index a3ea8ad..039f7fc 100644 (file)
@@ -1,7 +1,7 @@
 ;;; files.el --- file input and output commands for Emacs
 
 ;; Copyright (C) 1985, 86, 87, 92, 93,
-;;              94, 95, 1996 Free Software Foundation, Inc.
+;;              94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 
@@ -84,8 +84,9 @@ names that the old file had will now refer to the new (edited) file.
 The file's owner and group are unchanged.
 
 The choice of renaming or copying is controlled by the variables
-`backup-by-copying', `backup-by-copying-when-linked' and
-`backup-by-copying-when-mismatch'.  See also `backup-inhibited'."
+`backup-by-copying', `backup-by-copying-when-linked',
+`backup-by-copying-when-mismatch' and
+`backup-by-copying-when-privileged-mismatch'.  See also `backup-inhibited'."
   :type 'boolean
   :group 'backup)
 
@@ -120,16 +121,40 @@ This variable is relevant only if `backup-by-copying' is nil."
   :type 'boolean
   :group 'backup)
 
+(defcustom backup-by-copying-when-privileged-mismatch 200
+  "*Non-nil means create backups by copying to preserve a privileged owner.
+Renaming may still be used (subject to control of other variables)
+when it would not result in changing the owner of the file or if the owner
+has a user id greater than the value of this variable.  This is useful
+when low-numbered uid's are used for special system users (such as root)
+that must maintain ownership of certain files.
+This variable is relevant only if `backup-by-copying' and
+`backup-by-copying-when-mismatch' are nil."
+  :type '(choice (const nil) integer)
+  :group 'backup)
+
 (defvar backup-enable-predicate
-  '(lambda (name)
-     (or (< (length name) 5)
-        (not (string-equal "/tmp/" (substring name 0 5)))))
+  (lambda (name)
+    (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 -1)))
+            (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 -1)))))))
   "Predicate that looks at a file name and decides whether to make backups.
-Called with an absolute file name as argument, it returns t to enable backup.")
+Called with an absolute file name as argument, it returns t to enable backup.
+The default version checks for files in `temporary-file-directory' or
+`small-temporary-file-directory'.")
 
 (defcustom buffer-offer-save nil
-  "*Non-nil in a buffer means offer to save the buffer on exit
-even if the buffer is not visiting a file.
+  "*Non-nil in a buffer means always offer to save buffer on exit.
+Do so even if the buffer is not visiting a file.
 Automatically local in all buffers."
   :type 'boolean
   :group 'backup)
@@ -170,6 +195,19 @@ If the buffer is visiting a new file, the value is nil.")
 (defvar buffer-file-numbers-unique (not (memq system-type '(windows-nt)))
   "Non-nil means that buffer-file-number uniquely identifies files.")
 
+(defvar file-name-invalid-regexp
+  (cond ((and (eq system-type 'ms-dos) (not (msdos-long-file-names)))
+        (concat "^\\([^A-Z[-`a-z]\\|..+\\)?:\\|" ; colon except after drive
+                "[+, ;=|<>\"?*]\\|\\[\\|\\]\\|"  ; invalid characters
+                "[\000-\031]\\|"                 ; control characters
+                "\\(/\\.\\.?[^/]\\)\\|"          ; leading dots
+                "\\(/[^/.]+\\.[^/.]*\\.\\)"))    ; more than a single dot
+       ((memq system-type '(ms-dos windows-nt))
+        (concat "^\\([^A-Z[-`a-z]\\|..+\\)?:\\|" ; colon except after drive
+                "[|<>\"?*\000-\031]"))           ; invalid characters
+       (t "[\000]"))
+  "Regexp recognizing file names which aren't allowed by the filesystem.")
+
 (defcustom file-precious-flag nil
   "*Non-nil means protect against I/O errors while saving files.
 Some modes set this non-nil in particular buffers.
@@ -190,7 +228,9 @@ breaks any hard links between it and other files."
 t means make numeric backup versions unconditionally.
 nil means make them for files that have some already.
 `never' means do not make them."
-  :type 'boolean
+  :type '(choice (const :tag "Never" never)
+                (const :tag "If existing" nil)
+                (other :tag "Always" t))
   :group 'backup
   :group 'vc)
 
@@ -205,7 +245,7 @@ nil means make them for files that have some already.
 If nil, ask confirmation.  Any other value prevents any trimming."
   :type '(choice (const :tag "Delete" t)
                 (const :tag "Ask" nil)
-                (sexp :tag "Leave" :format "%t\n" other))
+                (other :tag "Leave" other))
   :group 'backup)
 
 (defcustom kept-old-versions 2
@@ -225,7 +265,7 @@ 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)
-                (sexp :tag "Ask" :format "%t\n" ask))
+                (other :tag "Ask" ask))
   :group 'editing-basics)
 
 (defcustom auto-save-default t
@@ -239,6 +279,23 @@ Normally auto-save files are written under other names."
   :type 'boolean
   :group 'auto-save)
 
+(defcustom auto-save-file-name-transforms
+  '(("\\`/[^/]*:\\(.+/\\)*\\(.*\\)" "/tmp/\\2"))
+  "*Transforms to apply to buffer file name before making auto-save file name.
+Each transform is a list (REGEXP REPLACEMENT):
+REGEXP is a regular expression to match against the file name.
+If it matches, `replace-match' is used to replace the
+matching part with REPLACEMENT.
+All the transforms in the list are tried, in the order they are listed.
+When one transform applies, its result is final;
+no further transforms are tried.
+
+The default value is set up to put the auto-save file into `/tmp'
+for editing a remote file."
+  :group 'auto-save
+  :type '(repeat (list (string :tag "Regexp") (string :tag "Replacement")))
+  :version "21.1")
+
 (defcustom save-abbrevs nil
   "*Non-nil means save word abbrevs too when files are saved.
 Loading an abbrev file sets this to t."
@@ -246,16 +303,24 @@ Loading an abbrev file sets this to t."
   :group 'abbrev)
 
 (defcustom find-file-run-dired t
-  "*Non-nil says run dired if `find-file' is given the name of a directory."
+  "*Non-nil means allow `find-file' to visit directories.
+To visit the directory, `find-file' runs `find-directory-functions'."
   :type 'boolean
   :group 'find-file)
 
+(defcustom find-directory-functions '(cvs-dired-noselect dired-noselect)
+  "*List of functions to try in sequence to visit a directory.
+Each function is called with the directory name as the sole argument
+and should return either a buffer or nil."
+  :type '(hook :options (cvs-dired-noselect dired-noselect))
+  :group 'find-file)
+
 ;;;It is not useful to make this a local variable.
 ;;;(put 'find-file-not-found-hooks 'permanent-local t)
 (defvar find-file-not-found-hooks nil
   "List of functions to be called for `find-file' on nonexistent file.
 These functions are called as soon as the error is detected.
-`buffer-file-name' is already set up.
+Variable `buffer-file-name' is already set up.
 The functions are called in the order given until one of them returns non-nil.")
 
 ;;;It is not useful to make this a local variable.
@@ -270,7 +335,8 @@ functions are called.")
 If one of them returns non-nil, the file is considered already written
 and the rest are not called.
 These hooks are considered to pertain to the visited file.
-So this list is cleared if you change the visited file name.
+So any buffer-local binding of `write-file-hooks' is
+discarded if you change the visited file name with \\[set-visited-file-name].
 
 Don't make this variable buffer-local; instead, use `local-write-file-hooks'.
 See also `write-contents-hooks'.")
@@ -311,14 +377,26 @@ See also `write-file-hooks'.")
 The value can be t, nil or something else.
 A value of t means file local variables specifications are obeyed;
 nil means they are ignored; anything else means query.
+This variable also controls use of major modes specified in
+a -*- line.
 
-The command \\[normal-mode] always obeys file local variable
-specifications and ignores this variable."
+The command \\[normal-mode], when used interactively,
+always obeys file local variable specifications and the -*- line,
+and ignores this variable."
   :type '(choice (const :tag "Obey" t)
                 (const :tag "Ignore" nil)
-                (sexp :tag "Query" :format "%t\n" other))
+                (other :tag "Query" other))
   :group 'find-file)
 
+(defvar local-enable-local-variables t
+  "Like `enable-local-variables' but meant for buffer-local bindings.
+The meaningful values are nil and non-nil.  The default is non-nil.
+If a major mode sets this to nil, buffer-locally, then any local
+variables list in the file will be ignored.
+
+This variable does not affect the use of major modes
+specified in a -*- line.")
+
 (defcustom enable-local-eval 'maybe
   "*Control processing of the \"variable\" `eval' in a file's local variables.
 The value can be t, nil or something else.
@@ -329,7 +407,7 @@ The command \\[normal-mode] always obeys local-variables lists
 and ignores this variable."
   :type '(choice (const :tag "Obey" t)
                 (const :tag "Ignore" nil)
-                (sexp :tag "Query" :format "%t\n" other))
+                (other :tag "Query" other))
   :group 'find-file)
 
 ;; Avoid losing in versions where CLASH_DETECTION is disabled.
@@ -343,11 +421,31 @@ and ignores this variable."
 (defvar view-read-only nil
   "*Non-nil means buffers visiting files read-only, do it in view mode.")
 
-;; This hook function provides support for ange-ftp host name
-;; completion.  It runs the usual ange-ftp hook, but only for
-;; completion operations.  Having this here avoids the need
-;; to load ange-ftp when it's not really in use.
+(defvar temporary-file-directory
+  (file-name-as-directory
+   (cond ((memq system-type '(ms-dos windows-nt))
+         (or (getenv "TEMP") (getenv "TMPDIR") (getenv "TMP") "c:/temp"))
+        ((memq system-type '(vax-vms axp-vms))
+         (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "SYS$SCRATCH:"))
+        (t
+         (or (getenv "TMPDIR") (getenv "TMP") (getenv "TEMP") "/tmp"))))
+  "The directory for writing temporary files.")
+
+(defvar small-temporary-file-directory
+  (if (eq system-type 'ms-dos) (getenv "TMPDIR"))
+  "The directory for writing small temporary files.
+If non-nil, this directory is used instead of `temporary-file-directory'
+by programs that create small temporary files.  This is for systems that
+have fast storage with limited space, such as a RAM disk.")
+
+;; The system null device. (Should reference NULL_DEVICE from C.)
+(defvar null-device "/dev/null" "The system null device.")
+
 (defun ange-ftp-completion-hook-function (op &rest args)
+  "Provides support for ange-ftp host name completion.
+Runs the usual ange-ftp hook, but only for completion operations."
+  ;; Having this here avoids the need to load ange-ftp when it's not
+  ;; really in use.
   (if (memq op '(file-name-completion file-name-all-completions))
       (apply 'ange-ftp-hook-function op args)
     (let ((inhibit-file-name-handlers
@@ -373,9 +471,6 @@ with a definition that really does change some file names."
   "Value of the CDPATH environment variable, as a list.
 Not actually set up until the first time you you use it.")
 
-(defvar path-separator ":"
-  "Character used to separate directories in search paths.")
-
 (defun parse-colon-path (cd-path)
   "Explode a colon-separated search path into a list of directory names."
   (and cd-path
@@ -436,7 +531,9 @@ colon-separated list of directories when resolving a relative directory name."
 (defun load-file (file)
   "Load the Lisp file named FILE."
   (interactive "fLoad file: ")
-  (load (expand-file-name file) nil nil t))
+  (let ((completion-ignored-extensions
+        (delete ".elc" completion-ignored-extensions)))
+    (load (expand-file-name file) nil nil t)))
 
 (defun load-library (library)
   "Load the library named LIBRARY.
@@ -444,10 +541,12 @@ This is an interface to the function `load'."
   (interactive "sLoad library: ")
   (load library))
 
-(defun file-local-copy (file &optional buffer)
+(defun file-local-copy (file)
   "Copy the file FILE into a temporary file on this machine.
 Returns the name of the local copy, or nil, if FILE is directly
 accessible."
+  ;; This formerly had an optional BUFFER argument that wasn't used by
+  ;; anything.
   (let ((handler (find-file-name-handler file 'file-local-copy)))
     (if handler
        (funcall handler 'file-local-copy file)
@@ -504,7 +603,7 @@ Do not specify them in other calls."
        (if handler
            (setq filename (funcall handler 'file-truename filename))
          ;; If filename contains a wildcard, newname will be the old name.
-         (if (string-match "[*?]" filename)
+         (if (string-match "[[*?]" filename)
              (setq newname filename)
            ;; If filename doesn't exist, newname will be nil.
            (setq newname (w32-long-file-name filename)))
@@ -609,51 +708,73 @@ do not put this buffer at the front of the list of recently selected ones."
     (pop-to-buffer buffer t norecord)
     (raise-frame (window-frame (selected-window)))))
 
-(defun find-file (filename)
+(defun find-file (filename &optional wildcards)
   "Edit file FILENAME.
 Switch to a buffer visiting file FILENAME,
-creating one if none already exists."
-  (interactive "FFind file: ")
-  (switch-to-buffer (find-file-noselect filename)))
-
-(defun find-file-other-window (filename)
+creating one if none already exists.
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and visit multiple files.  Wildcard expansion
+can be suppressed by setting `find-file-wildcards'."
+  (interactive "FFind file: \np")
+  (let ((value (find-file-noselect filename nil nil wildcards)))
+    (if (listp value)
+       (mapcar 'switch-to-buffer (nreverse value))
+      (switch-to-buffer value))))
+
+(defun find-file-other-window (filename &optional wildcards)
   "Edit file FILENAME, in another window.
 May create a new window, or reuse an existing one.
-See the function `display-buffer'."
-  (interactive "FFind file in other window: ")
-  (switch-to-buffer-other-window (find-file-noselect filename)))
+See the function `display-buffer'.
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and visit multiple files."
+  (interactive "FFind file in other window: \np")
+  (let ((value (find-file-noselect filename nil nil wildcards)))
+    (if (listp value)
+       (progn
+         (setq value (nreverse value))
+         (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)
+(defun find-file-other-frame (filename &optional wildcards)
   "Edit file FILENAME, in another frame.
 May create a new frame, or reuse an existing one.
-See the function `display-buffer'."
-  (interactive "FFind file in other frame: ")
-  (switch-to-buffer-other-frame (find-file-noselect filename)))
+See the function `display-buffer'.
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and visit multiple files."
+  (interactive "FFind file in other frame: \np")
+  (let ((value (find-file-noselect filename nil nil wildcards)))
+    (if (listp value)
+       (progn
+         (setq value (nreverse value))
+         (switch-to-buffer-other-frame (car value))
+         (mapcar 'switch-to-buffer (cdr value)))
+      (switch-to-buffer-other-frame value))))
 
-(defun find-file-read-only (filename)
+(defun find-file-read-only (filename &optional wildcards)
   "Edit file FILENAME but don't allow changes.
-Like \\[find-file] but marks buffer as read-only.
+Like `find-file' but marks buffer as read-only.
 Use \\[toggle-read-only] to permit editing."
-  (interactive "fFind file read-only: ")
-  (find-file filename)
+  (interactive "fFind file read-only: \np")
+  (find-file filename wildcards)
   (toggle-read-only 1)
   (current-buffer))
 
-(defun find-file-read-only-other-window (filename)
+(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 "fFind file read-only other window: ")
-  (find-file-other-window filename)
+  (interactive "fFind file read-only other window: \np")
+  (find-file-other-window filename wildcards)
   (toggle-read-only 1)
   (current-buffer))
 
-(defun find-file-read-only-other-frame (filename)
+(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 "fFind file read-only other frame: ")
-  (find-file-other-frame filename)
+  (interactive "fFind file read-only other frame: \np")
+  (find-file-other-frame filename wildcards)
   (toggle-read-only 1)
   (current-buffer))
 
@@ -733,11 +854,13 @@ otherwise a string <2> or <3> or ... is appended to get an unused name."
 Choose the buffer's name using `generate-new-buffer-name'."
   (get-buffer-create (generate-new-buffer-name name)))
 
-(defvar automount-dir-prefix "^/tmp_mnt/"
-  "Regexp to match the automounter prefix in a directory name.")
+(defcustom automount-dir-prefix "^/tmp_mnt/"
+  "Regexp to match the automounter prefix in a directory name."
+  :group 'files
+  :type 'regexp)
 
 (defvar abbreviated-home-dir nil
-  "The user's homedir abbreviated according to `directory-abbrev-list'.")
+  "The user's homedir abbreviated according to `directory-abbrev-alist'.")
 
 (defun abbreviate-file-name (filename)
   "Return a version of FILENAME shortened using `directory-abbrev-alist'.
@@ -830,144 +953,203 @@ If there is no such live buffer, return nil."
                 (setq list (cdr list))))
          found))))
 \f
-(defun find-file-noselect (filename &optional nowarn rawfile)
+(defcustom find-file-wildcards t
+  "*Non-nil means file-visiting commands should handle wildcards.
+For example, if you specify `*.c', that would visit all the files
+whose names match the pattern."
+  :group 'files
+  :version "20.4"
+  :type 'boolean)
+
+(defun find-file-noselect (filename &optional nowarn rawfile wildcards)
   "Read file FILENAME into a buffer and return the buffer.
 If a buffer exists visiting FILENAME, return that one, but
 verify that the file has not changed since visited or saved.
 The buffer is not selected, just returned to the caller.
 Optional first arg NOWARN non-nil means suppress any warning messages.
-Optional second arg RAWFILE non-nil means the file is read literally."
+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."
   (setq filename
        (abbreviate-file-name
         (expand-file-name filename)))
   (if (file-directory-p filename)
-      (if find-file-run-dired
-         (dired-noselect (if find-file-visit-truename
-                             (abbreviate-file-name (file-truename filename))
-                           filename))
-       (error "%s is a directory" filename))
-    (let* ((buf (get-file-buffer filename))
-          (truename (abbreviate-file-name (file-truename filename)))
-          (number (nthcdr 10 (file-attributes truename)))
-          ;; Find any buffer for a file which has same truename.
-          (other (and (not buf) (find-buffer-visiting filename)))
-          error)
-      ;; Let user know if there is a buffer with the same truename.
-      (if other
-         (progn
-           (or nowarn
-               (string-equal filename (buffer-file-name other))
-               (message "%s and %s are the same file"
-                        filename (buffer-file-name other)))
-           ;; Optionally also find that buffer.
-           (if (or find-file-existing-other-name find-file-visit-truename)
-               (setq buf other))))
-      (if buf
-         (or nowarn
-             (verify-visited-file-modtime buf)
-             (cond ((not (file-exists-p filename))
-                    (error "File %s no longer exists!" filename))
-                   ;; Certain files should be reverted automatically
-                   ;; if they have changed on disk and not in the buffer.
-                   ((and (not (buffer-modified-p buf))
-                         (let ((tail revert-without-query)
-                               (found nil))
-                           (while tail
-                             (if (string-match (car tail) filename)
-                                 (setq found t))
-                             (setq tail (cdr tail)))
-                           found))
-                    (with-current-buffer buf
-                     (message "Reverting file %s..." filename)
-                     (revert-buffer t t)
-                     (message "Reverting file %s...done" filename)))
-                   ((yes-or-no-p
-                     (if (string= (file-name-nondirectory filename)
-                                  (buffer-name buf))
-                         (format
-                          (if (buffer-modified-p buf)
-       "File %s changed on disk.  Discard your edits? "
-       "File %s changed on disk.  Reread from disk? ")
-                          (file-name-nondirectory filename))
-                       (format
-                        (if (buffer-modified-p buf)
-      "File %s changed on disk.  Discard your edits in %s? "
-      "File %s changed on disk.  Reread from disk into %s? ")
-                        (file-name-nondirectory filename)
-                        (buffer-name buf))))
-                    (with-current-buffer buf
-                      (revert-buffer t t)))
-                   ((not (eq rawfile (not (null find-file-literally))))
-                    (if rawfile
-                        (message "File is already visited, and not literally")
-                      (message "File is already visited, and visited literally")))))
-       (save-excursion
-;;; The truename stuff makes this obsolete.
-;;;      (let* ((link-name (car (file-attributes filename)))
-;;;             (linked-buf (and (stringp link-name)
-;;;                              (get-file-buffer link-name))))
-;;;        (if (bufferp linked-buf)
-;;;            (message "Symbolic link to file in buffer %s"
-;;;                     (buffer-name linked-buf))))
+      (or (and find-file-run-dired
+              (run-hook-with-args-until-success
+               'find-directory-functions
+               (if find-file-visit-truename
+                   (abbreviate-file-name (file-truename filename))
+                 filename)))
+         (error "%s is a directory" filename))
+    (if (and wildcards
+            find-file-wildcards
+            (not (string-match "\\`/:" filename))
+            (string-match "[[*?]" filename))
+       (let ((files (condition-case nil
+                        (file-expand-wildcards filename t)
+                      (error (list filename))))
+             (find-file-wildcards nil))
+         (if (null files)
+             (find-file-noselect filename)
+           (car (mapcar #'find-file-noselect files))))
+      (let* ((buf (get-file-buffer filename))
+            (truename (abbreviate-file-name (file-truename filename)))
+            (number (nthcdr 10 (file-attributes truename)))
+            ;; Find any buffer for a file which has same truename.
+            (other (and (not buf) (find-buffer-visiting filename))))
+       ;; Let user know if there is a buffer with the same truename.
+       (if other
+           (progn
+             (or nowarn
+                 (string-equal filename (buffer-file-name other))
+                 (message "%s and %s are the same file"
+                          filename (buffer-file-name other)))
+             ;; Optionally also find that buffer.
+             (if (or find-file-existing-other-name find-file-visit-truename)
+                 (setq buf other))))
+       (if buf
+           ;; We are using an existing buffer.
+           (progn
+             (or nowarn
+                 (verify-visited-file-modtime buf)
+                 (cond ((not (file-exists-p filename))
+                        (error "File %s no longer exists!" filename))
+                       ;; Certain files should be reverted automatically
+                       ;; if they have changed on disk and not in the buffer.
+                       ((and (not (buffer-modified-p buf))
+                             (let ((tail revert-without-query)
+                                   (found nil))
+                               (while tail
+                                 (if (string-match (car tail) filename)
+                                     (setq found t))
+                                 (setq tail (cdr tail)))
+                               found))
+                        (with-current-buffer buf
+                          (message "Reverting file %s..." filename)
+                          (revert-buffer t t)
+                          (message "Reverting file %s...done" filename)))
+                       ((yes-or-no-p
+                         (if (string= (file-name-nondirectory filename)
+                                      (buffer-name buf))
+                             (format
+                              (if (buffer-modified-p buf)
+                                  "File %s changed on disk.  Discard your edits? "
+                                "File %s changed on disk.  Reread from disk? ")
+                              (file-name-nondirectory filename))
+                           (format
+                            (if (buffer-modified-p buf)
+                                "File %s changed on disk.  Discard your edits in %s? "
+                              "File %s changed on disk.  Reread from disk into %s? ")
+                            (file-name-nondirectory filename)
+                            (buffer-name buf))))
+                        (with-current-buffer buf
+                          (revert-buffer t t)))))
+             (with-current-buffer buf
+               (when (not (eq (not (null rawfile))
+                              (not (null find-file-literally))))
+                 (if (buffer-modified-p)
+                     (if (y-or-n-p (if rawfile
+                                       "Save file and revisit literally? "
+                                     "Save file and revisit non-literally? "))
+                         (progn
+                           (save-buffer)
+                           (find-file-noselect-1 buf filename nowarn
+                                                 rawfile truename number))
+                       (if (y-or-n-p (if rawfile
+                                         "Discard your edits and revisit file literally? "
+                                       "Discard your edits and revisit file non-literally? "))
+                           (find-file-noselect-1 buf filename nowarn
+                                                 rawfile truename number)
+                         (error (if rawfile "File already visited non-literally"
+                                  "File already visited literally"))))
+                   (if (y-or-n-p (if rawfile
+                                     "Revisit file literally? "
+                                   "Revisit file non-literally? "))
+                       (find-file-noselect-1 buf filename nowarn
+                                             rawfile truename number)
+                     (error (if rawfile "File already visited non-literally"
+                              "File already visited literally"))))))
+             ;; Return the buffer we are using.
+             buf)
+         ;; Create a new buffer.
          (setq buf (create-file-buffer filename))
          (set-buffer-major-mode buf)
-         (set-buffer buf)
-         (erase-buffer)
-         (if rawfile
-             (condition-case ()
-                 (insert-file-contents-literally filename t)
-               (file-error
-                (when (and (file-exists-p filename)
-                           (not (file-readable-p filename)))
-                  (kill-buffer buf)
-                  (signal 'file-error (list "File is not readable"
-                                            filename)))
-                ;; Unconditionally set error
-                (setq error t)))
-           (condition-case ()
-               (insert-file-contents filename t)
-             (file-error
-              (when (and (file-exists-p filename)
-                         (not (file-readable-p filename)))
-                (kill-buffer buf)
-                (signal 'file-error (list "File is not readable"
-                                          filename)))
-              ;; Run find-file-not-found-hooks until one returns non-nil.
-              (or (run-hook-with-args-until-success 'find-file-not-found-hooks)
-                  ;; If they fail too, set error.
-                  (setq error t)))))
-         ;; Find the file's truename, and maybe use that as visited name.
+         ;; find-file-noselect-1 may use a different buffer.
+         (find-file-noselect-1 buf filename nowarn
+                               rawfile truename number))))))
+
+(defun find-file-noselect-1 (buf filename nowarn rawfile truename number)
+  (let ((inhibit-read-only t)
+       error)
+    (with-current-buffer buf
+      (kill-local-variable 'find-file-literally)
+      ;; Needed in case we are re-visiting the file with a different
+      ;; text representation.
+      (kill-local-variable 'buffer-file-coding-system)
+      (erase-buffer)
+      (and (default-value 'enable-multibyte-characters)
+          (not rawfile)
+          (set-buffer-multibyte t))
+      (if rawfile
+         (condition-case ()
+             (insert-file-contents-literally filename t)
+           (file-error
+            (when (and (file-exists-p filename)
+                       (not (file-readable-p filename)))
+              (kill-buffer buf)
+              (signal 'file-error (list "File is not readable"
+                                        filename)))
+            ;; Unconditionally set error
+            (setq error t)))
+       (condition-case ()
+           (insert-file-contents filename t)
+         (file-error
+          (when (and (file-exists-p filename)
+                     (not (file-readable-p filename)))
+            (kill-buffer buf)
+            (signal 'file-error (list "File is not readable"
+                                      filename)))
+          ;; Run find-file-not-found-hooks until one returns non-nil.
+          (or (run-hook-with-args-until-success 'find-file-not-found-hooks)
+              ;; If they fail too, set error.
+              (setq error t)))))
+      ;; Record the file's truename, and maybe use that as visited name.
+      (if (equal filename buffer-file-name)
          (setq buffer-file-truename truename)
-         (setq buffer-file-number number)
-         ;; On VMS, we may want to remember which directory in a search list
-         ;; the file was found in.
-         (and (eq system-type 'vax-vms)
-              (let (logical)
-                (if (string-match ":" (file-name-directory filename))
-                    (setq logical (substring (file-name-directory filename)
-                                             0 (match-beginning 0))))
-                (not (member logical find-file-not-true-dirname-list)))
-              (setq buffer-file-name buffer-file-truename))
-         (if find-file-visit-truename
-             (setq buffer-file-name
-                   (setq filename
-                         (expand-file-name buffer-file-truename))))
-         ;; Set buffer's default directory to that of the file.
-         (setq default-directory (file-name-directory filename))
-         ;; Turn off backup files for certain file names.  Since
-         ;; this is a permanent local, the major mode won't eliminate it.
-         (and (not (funcall backup-enable-predicate buffer-file-name))
-              (progn
-                (make-local-variable 'backup-inhibited)
-                (setq backup-inhibited t)))
-         (if rawfile
-             (progn
-               (setq enable-multibyte-characters nil)
-               (make-local-variable 'find-file-literally)
-               (setq find-file-literally t))
-           (after-find-file error (not nowarn))
-           (setq buf (current-buffer)))))
-      buf)))
+       (setq buffer-file-truename
+             (abbreviate-file-name (file-truename buffer-file-name))))
+      (setq buffer-file-number number)
+      ;; On VMS, we may want to remember which directory in a search list
+      ;; the file was found in.
+      (and (eq system-type 'vax-vms)
+          (let (logical)
+            (if (string-match ":" (file-name-directory filename))
+                (setq logical (substring (file-name-directory filename)
+                                         0 (match-beginning 0))))
+            (not (member logical find-file-not-true-dirname-list)))
+          (setq buffer-file-name buffer-file-truename))
+      (if find-file-visit-truename
+         (setq buffer-file-name
+               (setq filename
+                     (expand-file-name buffer-file-truename))))
+      ;; Set buffer's default directory to that of the file.
+      (setq default-directory (file-name-directory buffer-file-name))
+      ;; Turn off backup files for certain file names.  Since
+      ;; this is a permanent local, the major mode won't eliminate it.
+      (and (not (funcall backup-enable-predicate buffer-file-name))
+          (progn
+            (make-local-variable 'backup-inhibited)
+            (setq backup-inhibited t)))
+      (if rawfile
+         (progn
+           (set-buffer-multibyte nil)
+           (setq buffer-file-coding-system 'no-conversion)
+           (make-local-variable 'find-file-literally)
+           (setq find-file-literally t))
+       (after-find-file error (not nowarn)))
+      (current-buffer))))
 \f
 (defun insert-file-contents-literally (filename &optional visit beg end replace)
   "Like `insert-file-contents', but only reads in the file literally.
@@ -1011,7 +1193,7 @@ Don't call it from programs!  Use `insert-file-contents-literally' instead.
 This is a permanent local.")
 (put 'find-file-literally 'permanent-local t)
 
-(defun find-file-literally (filename) 
+(defun find-file-literally (filename)
   "Visit file FILENAME with no conversion of any kind.
 Format conversion and character code conversion are both disabled,
 and multibyte characters are disabled in the resulting buffer.
@@ -1053,10 +1235,15 @@ unless NOMODES is non-nil."
           (msg
            (cond ((and error (file-attributes buffer-file-name))
                   (setq buffer-read-only t)
-                  "File exists, but cannot be read.")
+                  "File exists, but cannot be read")
                  ((not buffer-read-only)
                   (if (and warn
-                           (file-newer-than-file-p (make-auto-save-file-name)
+                           ;; No need to warn if buffer is auto-saved
+                           ;; under the name of the visited file.
+                           (not (and buffer-file-name
+                                     auto-save-visited-file-name))
+                           (file-newer-than-file-p (or buffer-auto-save-file-name
+                                                       (make-auto-save-file-name))
                                                    buffer-file-name))
                       (format "%s has auto save data; consider M-x recover-file"
                               (file-name-nondirectory buffer-file-name))
@@ -1072,16 +1259,22 @@ unless NOMODES is non-nil."
                  (t
                   (setq buffer-read-only nil)
                   (if (file-exists-p (file-name-directory (directory-file-name (file-name-directory buffer-file-name))))
-                      "Use M-x make-dir RET RET to create the directory"
-                    "Use C-u M-x make-dir RET RET to create directory and its parents")))))
+                      "Use M-x make-directory RET RET to create the directory"
+                    "Use C-u M-x make-directory RET RET to create directory and its parents")))))
       (if msg
          (progn
            (message msg)
            (or not-serious (sit-for 1 nil t)))))
     (if (and auto-save-default (not noauto))
        (auto-save-mode t)))
+  ;; Make people do a little extra work (C-x C-q)
+  ;; before altering a backup file.
+  (if (backup-file-name-p buffer-file-name)
+      (setq buffer-read-only t))
   (if nomodes
       nil
+    (and view-read-only view-mode
+        (view-mode-disable))
     (normal-mode t)
     (if (and buffer-read-only view-read-only
             (not (eq (get major-mode 'mode-class) 'special)))
@@ -1094,10 +1287,15 @@ Also sets up any specified local variables of the file.
 Uses the visited file name, the -*- line, and the local variables spec.
 
 This function is called automatically from `find-file'.  In that case,
-we may set up specified local variables depending on the value of
-`enable-local-variables': if it is t, we do; if it is nil, we don't;
-otherwise, we query.  `enable-local-variables' is ignored if you
-run `normal-mode' explicitly."
+we may set up the file-specified mode and local variables,
+depending on the value of `enable-local-variables': if it is t, we do;
+if it is nil, we don't; otherwise, we query.
+In addition, if `local-enable-local-variables' is nil, we do
+not set local variables (though we do notice a mode specified with -*-.)
+
+`enable-local-variables' is ignored if you run `normal-mode' interactively,
+or from Lisp without specifying the optional argument FIND-FILE;
+in that case, this function acts as if `enable-local-variables' were t."
   (interactive)
   (or find-file (funcall (or default-major-mode 'fundamental-mode)))
   (condition-case err
@@ -1118,10 +1316,6 @@ run `normal-mode' explicitly."
     ("\\.tex\\'" . tex-mode)
     ("\\.ltx\\'" . latex-mode)
     ("\\.el\\'" . emacs-lisp-mode)
-    ("\\.mm\\'" . nroff-mode)
-    ("\\.me\\'" . nroff-mode)
-    ("\\.ms\\'" . nroff-mode)
-    ("\\.man\\'" . nroff-mode)
     ("\\.scm\\'" . scheme-mode)
     ("\\.l\\'" . lisp-mode)
     ("\\.lisp\\'" . lisp-mode)
@@ -1146,7 +1340,7 @@ run `normal-mode' explicitly."
     ("\\.m\\'" . objc-mode)
     ("\\.java\\'" . java-mode)
     ("\\.mk\\'" . makefile-mode)
-    ("\\(M\\|m\\|GNUm\\)akefile\\(.in\\)?\\'" . makefile-mode)
+    ("\\(M\\|m\\|GNUm\\)akefile\\(\\.in\\)?\\'" . makefile-mode)
     ("\\.am\\'" . makefile-mode)       ;For Automake.
 ;;; Less common extensions come here
 ;;; so more common ones above are found faster.
@@ -1156,18 +1350,24 @@ run `normal-mode' explicitly."
     ("\\.S\\'" . asm-mode)
     ("\\.asm\\'" . asm-mode)
     ("ChangeLog\\'" . change-log-mode)
-    ("change.log\\'" . change-log-mode)
+    ("change\\.log\\'" . change-log-mode)
     ("changelo\\'" . change-log-mode)
-    ("ChangeLog.[0-9]+\\'" . change-log-mode)
+    ("ChangeLog\\.[0-9]+\\'" . change-log-mode)
     ;; for MSDOS and MS-Windows (which are case-insensitive)
     ("changelog\\'" . change-log-mode)
-    ("changelog.[0-9]+\\'" . change-log-mode)
+    ("changelog\\.[0-9]+\\'" . change-log-mode)
     ("\\$CHANGE_LOG\\$\\.TXT" . change-log-mode)
     ("\\.scm\\.[0-9]*\\'" . scheme-mode)
     ("\\.[ck]?sh\\'\\|\\.shar\\'\\|/\\.z?profile\\'" . sh-mode)
-    ("/\\.\\(bash_profile\\|z?login\\|bash_login\\|z?logout\\)\\'" . sh-mode)
-    ("/\\.\\(bash_logout\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
-    ("/\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
+    ("\\(/\\|\\`\\)\\.\\(bash_profile\\|z?login\\|bash_login\\|z?logout\\)\\'" . sh-mode)
+    ("\\(/\\|\\`\\)\\.\\(bash_logout\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
+    ("\\(/\\|\\`\\)\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
+    ("\\.m?spec$" . sh-mode)
+    ("\\.mm\\'" . nroff-mode)
+    ("\\.me\\'" . nroff-mode)
+    ("\\.ms\\'" . nroff-mode)
+    ("\\.man\\'" . nroff-mode)
+    ("\\.\\(u?lpc\\|pike\\|pmod\\)\\'" . pike-mode)
 ;;; The following should come after the ChangeLog pattern
 ;;; for the sake of ChangeLog.1, etc.
 ;;; and after the .scm.[0-9] pattern too.
@@ -1178,6 +1378,7 @@ run `normal-mode' explicitly."
     ("\\.clo\\'" . latex-mode)         ;LaTeX 2e class option
     ("\\.bbl\\'" . latex-mode)
     ("\\.bib\\'" . bibtex-mode)
+    ("\\.sql\\'" . sql-mode)
     ("\\.m4\\'" . m4-mode)
     ("\\.mc\\'" . m4-mode)
     ("\\.mf\\'" . metafont-mode)
@@ -1193,6 +1394,7 @@ run `normal-mode' explicitly."
     ("\\.sim\\'" . simula-mode)
     ("\\.mss\\'" . scribe-mode)
     ("\\.f90\\'" . f90-mode)
+    ("\\.pro\\'" . idlwave-mode)
     ("\\.lsp\\'" . lisp-mode)
     ("\\.awk\\'" . awk-mode)
     ("\\.prolog\\'" . prolog-mode)
@@ -1204,21 +1406,37 @@ run `normal-mode' explicitly."
     ("\\`/tmp/Re" . text-mode)
     ("/Message[0-9]*\\'" . text-mode)
     ("/drafts/[0-9]+\\'" . mh-letter-mode)
+    ("\\.zone\\'" . zone-mode)
     ;; some news reader is reported to use this
     ("\\`/tmp/fol/" . text-mode)
     ("\\.y\\'" . c-mode)
     ("\\.lex\\'" . c-mode)
     ("\\.oak\\'" . scheme-mode)
     ("\\.sgml?\\'" . sgml-mode)
+    ("\\.xml\\'" . sgml-mode)
     ("\\.dtd\\'" . sgml-mode)
     ("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
+    ("\\.idl\\'" . idl-mode)
     ;; .emacs following a directory delimiter
     ;; in Unix, MSDOG or VMS syntax.
     ("[]>:/\\]\\..*emacs\\'" . emacs-lisp-mode)
+    ("\\`\\..*emacs\\'" . emacs-lisp-mode)
     ;; _emacs following a directory delimiter
     ;; in MsDos syntax
     ("[:/]_emacs\\'" . emacs-lisp-mode)
-    ("\\.ml\\'" . lisp-mode))
+    ("/crontab\\.X*[0-9]+\\'" . shell-script-mode)
+    ("\\.ml\\'" . lisp-mode)
+    ("\\.asn$" . snmp-mode)
+    ("\\.mib$" . snmp-mode)
+    ("\\.smi$" . snmp-mode)
+    ("\\.as2$" . snmpv2-mode)
+    ("\\.mi2$" . snmpv2-mode)
+    ("\\.sm2$" . snmpv2-mode)
+    ("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
+    ("\\.[eE]?[pP][sS]$" . ps-mode)
+    ("configure\\.in\\'" . autoconf-mode)
+    ("EBROWSE\\'" . ebrowse-tree-mode)
+    ("\\.ebrowse\\'" . ebrowse-tree-mode))
   "\
 Alist of filename patterns vs corresponding major mode functions.
 Each element looks like (REGEXP . FUNCTION) or (REGEXP FUNCTION NON-NIL).
@@ -1230,6 +1448,7 @@ 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.")
 
+
 (defvar interpreter-mode-alist
   '(("perl" . perl-mode)
     ("perl5" . perl-mode)
@@ -1254,6 +1473,7 @@ REGEXP and search the list again for another match.")
     ("oash" . sh-mode)
     ("pdksh" . sh-mode)
     ("rc" . sh-mode)
+    ("rpm" . sh-mode)
     ("sh" . sh-mode)
     ("sh5" . sh-mode)
     ("tcsh" . sh-mode)
@@ -1263,7 +1483,10 @@ REGEXP and search the list again for another match.")
     ("tail" . text-mode)
     ("more" . text-mode)
     ("less" . text-mode)
-    ("pg" . text-mode))
+    ("pg" . text-mode)
+    ("make" . makefile-mode)           ; Debian uses this
+    ("guile" . scheme-mode)
+    ("clisp" . lisp-mode))
   "Alist mapping interpreter names to major modes.
 This alist applies to files whose first line starts with `#!'.
 Each element looks like (INTERPRETER . MODE).
@@ -1279,10 +1502,6 @@ If it matches, mode MODE is selected.")
 When checking `inhibit-first-line-modes-regexps', we first discard
 from the end of the file name anything that matches one of these regexps.")
 
-(defvar user-init-file
-  "" ; set by command-line
-  "File name including directory of user's initialization file.")
-
 (defun set-auto-mode (&optional just-from-file-name)
   "Select major mode appropriate for current buffer.
 This checks for a -*- mode tag in the buffer's text,
@@ -1383,15 +1602,20 @@ and we don't even do that unless it would come from the file name."
                  (if (string-match (car (car alist)) name)
                      (if (and (consp (cdr (car alist)))
                               (nth 2 (car alist)))
-                         (progn
-                           (setq mode (car (cdr (car alist)))
-                                 name (substring name 0 (match-beginning 0))
-                                 keep-going t))
+                         (setq mode (car (cdr (car alist)))
+                               name (substring name 0 (match-beginning 0))
+                               keep-going t)
                        (setq mode (cdr (car alist))
                              keep-going nil)))
                  (setq alist (cdr alist))))
              (if mode
-                 (funcall mode)
+                 ;; When JUST-FROM-FILE-NAME is set,
+                 ;; we are working on behalf of set-visited-file-name.
+                 ;; In that case, if the major mode specified is the
+                 ;; same one we already have, don't actually reset it.
+                 ;; We don't want to lose minor modes such as Font Lock.
+                 (unless (and just-from-file-name (eq mode major-mode))
+                   (funcall mode))
                ;; If we can't deduce a mode from the file name,
                ;; look for an interpreter specified in the first line.
                ;; As a special case, allow for things like "#!/bin/env perl",
@@ -1399,9 +1623,9 @@ and we don't even do that unless it would come from the file name."
                (let ((interpreter
                       (save-excursion
                         (goto-char (point-min))
-                        (if (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")
-                            (buffer-substring (match-beginning 2)
-                                              (match-end 2))
+                        (if (looking-at "#![ \t]?\\([^ \t\n]*\
+/bin/env[ \t]\\)?\\([^ \t\n]+\\)")
+                            (match-string 2)
                           "")))
                      elt)
                  ;; Map interpreter name to a mode.
@@ -1412,14 +1636,16 @@ and we don't even do that unless it would come from the file name."
                        (funcall (cdr elt))))))))))))
 
 (defun hack-local-variables-prop-line ()
-  ;; Set local variables specified in the -*- line.
-  ;; Ignore any specification for `mode:' and `coding:';
-  ;; set-auto-mode should already have handled `mode:',
-  ;; set-auto-coding should already have handled `coding:'.
+  "Set local variables specified in the -*- line.
+Ignore any specification for `mode:' and `coding:';
+`set-auto-mode' should already have handled `mode:',
+`set-auto-coding' should already have handled `coding:'."
   (save-excursion
     (goto-char (point-min))
     (let ((result nil)
-         (end (save-excursion (end-of-line (and (looking-at "^#!") 2)) (point))))
+         (end (save-excursion (end-of-line (and (looking-at "^#!") 2)) (point)))
+         (enable-local-variables
+          (and local-enable-local-variables enable-local-variables)))
       ;; Parse the -*- line into the `result' alist.
       (cond ((not (search-forward "-*-" end t))
             ;; doesn't have one.
@@ -1436,7 +1662,7 @@ and we don't even do that unless it would come from the file name."
                 (error "-*- not terminated before end of line")))
             (while (< (point) end)
               (or (looking-at "[ \t]*\\([^ \t\n:]+\\)[ \t]*:[ \t]*")
-                  (error "malformed -*- line"))
+                  (error "Malformed -*- line"))
               (goto-char (match-end 0))
               ;; There used to be a downcase here,
               ;; but the manual didn't say so,
@@ -1491,7 +1717,9 @@ is specified, returning t if it is specified."
   (unless mode-only
     (hack-local-variables-prop-line))
   ;; Look for "Local variables:" line in last page.
-  (let (mode-specified)
+  (let (mode-specified
+       (enable-local-variables
+        (and local-enable-local-variables enable-local-variables)))
     (save-excursion
       (goto-char (point-max))
       (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
@@ -1599,9 +1827,9 @@ is specified, returning t if it is specified."
 (defun hack-one-local-variable-quotep (exp)
   (and (consp exp) (eq (car exp) 'quote) (consp (cdr exp))))
 
-;; "Set" one variable in a local variables spec.
-;; A few variable names are treated specially.
 (defun hack-one-local-variable (var val)
+  "\"Set\" one variable in a local variables spec.
+A few variable names are treated specially."
   (cond ((eq var 'mode)
         (funcall (intern (concat (downcase (symbol-name val))
                                  "-mode"))))
@@ -1614,7 +1842,7 @@ is specified, returning t if it is specified."
        ;; Likewise for setting hook variables.
        ((or (get var 'risky-local-variable)
             (and
-             (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-command$"
+             (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-command$\\|-predicate$"
                            (symbol-name var))
              (not (get var 'safe-local-variable))))
         ;; Permit evalling a put of a harmless property.
@@ -1640,13 +1868,15 @@ is specified, returning t if it is specified."
                                   (beginning-of-line)
                                   (set-window-start (selected-window) (point)))
                                 (setq enable-local-eval
-                                      (y-or-n-p (format "Process `eval' or hook local variables in file %s? "
-                                                        (file-name-nondirectory buffer-file-name)))))))))
+                                      (y-or-n-p (format "Process `eval' or hook local variables in %s? "
+                                                        (if buffer-file-name
+                                                            (concat "file " (file-name-nondirectory buffer-file-name))
+                                                          (concat "buffer " (buffer-name)))))))))))
             (if (eq var 'eval)
                 (save-excursion (eval val))
               (make-local-variable var)
               (set var val))
-          (message "Ignoring `eval:' in file's local variables")))
+          (message "Ignoring `eval:' in the local variables list")))
        ;; Ordinary variable, really set it.
        (t (make-local-variable var)
           (set var val))))
@@ -1771,31 +2001,37 @@ the old visited file has been renamed to the new name FILENAME."
 
 (defun write-file (filename &optional confirm)
   "Write current buffer into file FILENAME.
-Makes buffer visit that file, and marks it not modified.
-If the buffer is already visiting a file, you can specify
-a directory name as FILENAME, to write a file of the same
-old name in that directory.
+This makes the buffer visit that file, and marks it as not modified.
+
+If you specify just a directory name as FILENAME, that means to use
+the default file name but in that directory.  You can also yank
+the default file name into the minibuffer to edit it, using M-n.
+
+If the buffer is not already visiting a file, the default file name
+for the output file is the buffer name.
 
-If optional second arg CONFIRM is non-nil,
-ask for confirmation for overwriting an existing file.
+If optional second arg CONFIRM is non-nil, this function
+asks for confirmation before overwriting an existing file.
 Interactively, confirmation is required unless you supply a prefix argument."
 ;;  (interactive "FWrite file: ")
   (interactive
    (list (if buffer-file-name
             (read-file-name "Write file: "
                                 nil nil nil nil)
-          (read-file-name "Write file: "
-                              (cdr (assq 'default-directory
-                                         (buffer-local-variables)))
-                              nil nil (buffer-name)))
+          (read-file-name "Write file: " default-directory
+                          (expand-file-name
+                           (file-name-nondirectory (buffer-name))
+                           default-directory)
+                          nil nil))
         (not current-prefix-arg)))
   (or (null filename) (string-equal filename "")
       (progn
        ;; If arg is just a directory,
-       ;; use same file name, but in that directory.
-       (if (and (file-directory-p filename) buffer-file-name)
+       ;; use the default file name, but in that directory.
+       (if (file-directory-p filename)
            (setq filename (concat (file-name-as-directory filename)
-                                  (file-name-nondirectory buffer-file-name))))
+                                  (file-name-nondirectory
+                                   (or buffer-file-name (buffer-name))))))
        (and confirm
             (file-exists-p filename)
             (or (y-or-n-p (format "File `%s' exists; overwrite? " filename))
@@ -1847,14 +2083,19 @@ no longer accessible under its old name."
                  ;; Actually write the back up file.
                  (condition-case ()
                      (if (or file-precious-flag
-    ;                    (file-symlink-p buffer-file-name)
+    ;                        (file-symlink-p buffer-file-name)
                              backup-by-copying
                              (and backup-by-copying-when-linked
                                   (> (file-nlinks real-file-name) 1))
-                             (and backup-by-copying-when-mismatch
+                             (and (or backup-by-copying-when-mismatch
+                                      (integerp backup-by-copying-when-privileged-mismatch))
                                   (let ((attr (file-attributes real-file-name)))
-                                    (or (nth 9 attr)
-                                        (not (file-ownership-preserved-p real-file-name))))))
+                                    (and (or backup-by-copying-when-mismatch
+                                             (and (integerp (nth 2 attr))
+                                                  (integerp backup-by-copying-when-privileged-mismatch)
+                                                  (<= (nth 2 attr) backup-by-copying-when-privileged-mismatch)))
+                                         (or (nth 9 attr)
+                                             (not (file-ownership-preserved-p real-file-name)))))))
                          (condition-case ()
                              (copy-file real-file-name backupname t t)
                            (file-error
@@ -1896,7 +2137,7 @@ no longer accessible under its old name."
            (file-error nil))))))
 
 (defun file-name-sans-versions (name &optional keep-backup-version)
-  "Return FILENAME sans backup versions or strings.
+  "Return file NAME sans backup versions or strings.
 This is a separate procedure so your site-init or startup file can
 redefine it.
 If the optional argument KEEP-BACKUP-VERSION is non-nil,
@@ -1923,7 +2164,7 @@ we do not remove backup version numbers, only true file version numbers."
                         (length name))))))))
 
 (defun file-ownership-preserved-p (file)
-  "Returns t if deleting FILE and rewriting it would preserve the owner."
+  "Return t if deleting FILE and rewriting it would preserve the owner."
   (let ((handler (find-file-name-handler file 'file-ownership-preserved-p)))
     (if handler
        (funcall handler 'file-ownership-preserved-p file)
@@ -1962,19 +2203,94 @@ the value is \"\"."
         (if period
             "")))))
 
+(defcustom make-backup-file-name-function nil
+  "A function to use instead of the default `make-backup-file-name'.
+A value of nil gives the default `make-backup-file-name' behaviour.
+
+This could be buffer-local to do something special for for specific
+files.  If you define it, you may need to change `backup-file-name-p'
+and `file-name-sans-versions' too.
+
+See also `backup-directory-alist'."
+  :group 'backup
+  :type '(choice (const :tag "Default" nil)
+                (function :tag "Your function")))
+
+(defcustom backup-directory-alist nil
+  "Alist of filename patterns and backup directory names.
+Each element looks like (REGEXP . DIRECTORY).  Backups of files with
+names matching REGEXP will be made in DIRECTORY.  DIRECTORY may be
+relative or absolute.  If it is absolute, so that all matching files
+are backed up into the same directory, the file names in this
+directory will be the full name of the file backed up with all
+directory separators changed to `|' to prevent clashes.  This will not
+work correctly if your filesystem truncates the resulting name.
+
+For the common case of all backups going into one directory, the alist
+should contain a single element pairing \".\" with the appropriate
+directory name.
+
+If this variable is nil, or it fails to match a filename, the backup
+is made in the original file's directory.
+
+On MS-DOS filesystems without long names this variable is always
+ignored."
+  :group 'backup
+  :type '(repeat (cons (regexp :tag "Regexp macthing filename")
+                      (directory :tag "Backup directory name"))))
+
 (defun make-backup-file-name (file)
   "Create the non-numeric backup file name for FILE.
-This is a separate function so you can redefine it for customization."
-  (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 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.
+
+Otherwise 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) "~"))))
+
+(defun make-backup-file-name-1 (file)
+  "Subroutine of `make-backup-file-name' and `find-backup-file-name'."
+  (let ((alist backup-directory-alist)
+       elt backup-directory)
+    (while alist
+      (setq elt (pop alist))
+      (if (string-match (car elt) file)
+         (setq backup-directory (cdr elt)
+               alist nil)))
+    (if (null backup-directory)
+       file
+      (unless (file-exists-p backup-directory)
+       (condition-case nil
+           (make-directory backup-directory 'parents)
+         (file-error file)))
+      (if (file-name-absolute-p backup-directory)
+         ;; Make the name unique by substituting directory
+         ;; separators.  It may not really be worth bothering about
+         ;; doubling `|'s in the original name...
+         (expand-file-name
+          (subst-char-in-string
+           directory-sep-char ?|
+           (replace-regexp-in-string "|" "||" file))
+          backup-directory)
+       (expand-file-name (file-name-nondirectory file)
+                         (file-name-as-directory
+                          (expand-file-name backup-directory
+                                            (file-name-directory file))))))))
 
 (defun backup-file-name-p (file)
   "Return non-nil if FILE is a backup file name (numeric or not).
@@ -1985,11 +2301,10 @@ You may need to redefine `file-name-sans-versions' as well."
 (defvar backup-extract-version-start)
 
 ;; This is used in various files.
-;; The usage of bv-length is not very clean,
-;; but I can't see a good alternative,
-;; so as of now I am leaving it alone.
+;; The usage of backup-extract-version-start is not very clean,
+;; but I can't see a good alternative, so as of now I am leaving it alone.
 (defun backup-extract-version (fn)
-  "Given the name of a numeric backup file, return the backup number.
+  "Given the name of a numeric backup file, FN, return the backup number.
 Uses the free variable `backup-extract-version-start', whose value should be
 the index in the name where the version number begins."
   (if (and (string-match "[0-9]+~$" fn backup-extract-version-start)
@@ -2000,47 +2315,49 @@ the index in the name where the version number begins."
 ;; I believe there is no need to alter this behavior for VMS;
 ;; since backup files are not made on VMS, it should not get called.
 (defun find-backup-file-name (fn)
-  "Find a file name for a backup file, and suggestions for deletions.
+  "Find a file name for a backup file FN, and suggestions for deletions.
 Value is a list whose car is the name for the backup file
- and whose cdr is a list of old versions to consider deleting now.
-If the value is nil, don't make a backup."
+and whose cdr is a list of old versions to consider deleting now.
+If the value is nil, don't make a backup.
+Uses `backup-directory-alist' in the same way as does
+`make-backup-file-name'."
   (let ((handler (find-file-name-handler fn 'find-backup-file-name)))
     ;; Run a handler for this function so that ange-ftp can refuse to do it.
     (if handler
        (funcall handler 'find-backup-file-name fn)
       (if (eq version-control 'never)
          (list (make-backup-file-name fn))
-       (let* ((base-versions (concat (file-name-nondirectory fn) ".~"))
+       (let* ((basic-name (make-backup-file-name-1 fn))
+              (base-versions (concat (file-name-nondirectory basic-name)
+                                     ".~"))
               (backup-extract-version-start (length base-versions))
-              possibilities
-              (versions nil)
               (high-water-mark 0)
-              (deserve-versions-p nil)
-              (number-to-delete 0))
+              (number-to-delete 0)
+              possibilities deserve-versions-p versions)
          (condition-case ()
              (setq possibilities (file-name-all-completions
                                   base-versions
-                                  (file-name-directory fn))
-                   versions (sort (mapcar
-                                   (function backup-extract-version)
-                                   possibilities)
-                                  '<)
+                                  (file-name-directory basic-name))
+                   versions (sort (mapcar #'backup-extract-version
+                                          possibilities)
+                                  #'<)
                    high-water-mark (apply 'max 0 versions)
                    deserve-versions-p (or version-control
                                           (> high-water-mark 0))
                    number-to-delete (- (length versions)
-                                       kept-old-versions kept-new-versions -1))
-           (file-error
-            (setq possibilities nil)))
+                                       kept-old-versions
+                                       kept-new-versions
+                                       -1))
+           (file-error (setq possibilities nil)))
          (if (not deserve-versions-p)
-             (list (make-backup-file-name fn))
-           (cons (concat fn ".~" (int-to-string (1+ high-water-mark)) "~")
+             (list (concat basic-name "~"))
+           (cons (format "%s.~%d~" basic-name (1+ high-water-mark))
                  (if (and (> number-to-delete 0)
                           ;; Delete nothing if there is overflow
                           ;; in the number of versions to keep.
                           (>= (+ kept-new-versions kept-old-versions -1) 0))
-                     (mapcar (function (lambda (n)
-                                         (concat fn ".~" (int-to-string n) "~")))
+                     (mapcar (lambda (n)
+                               (format "%s.~%d~" basic-name n))
                              (let ((v (nthcdr kept-old-versions versions)))
                                (rplacd (nthcdr (1- number-to-delete) v) ())
                                v))))))))))
@@ -2050,7 +2367,7 @@ If the value is nil, don't make a backup."
   (car (cdr (file-attributes filename))))
 
 (defun file-relative-name (filename &optional directory)
-  "Convert FILENAME to be relative to DIRECTORY (default: default-directory).
+  "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 this is impossible (which can happen on MSDOS and Windows
@@ -2100,7 +2417,7 @@ With 3 \\[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 argument of 0, never makes the previous version into a backup file.
+With 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
  FOO.~i~ for various integers i.  A non-numbered backup file is called FOO~.
@@ -2114,7 +2431,13 @@ We don't want excessive versions piling up, so there are variables
  Defaults are 2 old versions and 2 new.
 `dired-kept-versions' controls dired's clean-directory (.) command.
 If `delete-old-versions' is nil, system will query user
- before trimming versions.  Otherwise it does it silently."
+ before trimming versions.  Otherwise it does it silently.
+
+If `vc-make-backup-files' is nil, which is the default,
+ no backup files are made for files managed by version control.
+ (This is because the version control system itself records previous versions.)
+
+See the subroutine `basic-save-buffer' for more information."
   (interactive "p")
   (let ((modp (buffer-modified-p))
        (large (> (buffer-size) 50000))
@@ -2138,14 +2461,31 @@ the last real save, but optional arg FORCE non-nil means delete anyway."
           (file-error nil))
         (set-buffer-auto-saved))))
 
+(defvar auto-save-hook nil
+  "Normal hook run just before auto-saving.")
+
 (defvar after-save-hook nil
   "Normal hook that is run after a buffer is saved to its file.")
 
+(defvar save-buffer-coding-system nil
+  "If non-nil, use this coding system for saving the buffer.
+More precisely, use this coding system in place of the
+value of `buffer-file-coding-system', when saving the buffer.
+Calling `write-region' for any purpose other than saving the buffer
+will still use `buffer-file-coding-system'; this variable has no effect
+in such cases.")
+
+(make-variable-buffer-local 'save-buffer-coding-system)
+(put 'save-buffer-coding-system 'permanent-local t)
+
 (defun basic-save-buffer ()
   "Save the current buffer in its visited file, if it has been modified.
-After saving the buffer, run `after-save-hook'."
+The hooks `write-contents-hooks', `local-write-file-hooks' and
+`write-file-hooks' get a chance to do the job of saving; if they do not,
+then the buffer is saved in the visited file file in the usual way.
+After saving the buffer, this function runs `after-save-hook'."
   (interactive)
-  (save-excursion
+  (save-current-buffer
     ;; In an indirect buffer, save its base buffer instead.
     (if (buffer-base-buffer)
        (set-buffer (buffer-base-buffer)))
@@ -2183,18 +2523,19 @@ After saving the buffer, run `after-save-hook'."
              (error "Save not confirmed"))
          (save-restriction
            (widen)
-           (and (> (point-max) 1)
-                (/= (char-after (1- (point-max))) ?\n)
-                (not (and (eq selective-display t)
-                          (= (char-after (1- (point-max))) ?\r)))
-                (or (eq require-final-newline t)
-                    (and require-final-newline
-                         (y-or-n-p
-                          (format "Buffer %s does not end in newline.  Add one? "
-                                  (buffer-name)))))
-                (save-excursion
-                  (goto-char (point-max))
-                  (insert ?\n)))
+           (save-excursion
+             (and (> (point-max) 1)
+                  (/= (char-after (1- (point-max))) ?\n)
+                  (not (and (eq selective-display t)
+                            (= (char-after (1- (point-max))) ?\r)))
+                  (or (eq require-final-newline t)
+                      (and require-final-newline
+                           (y-or-n-p
+                            (format "Buffer %s does not end in newline.  Add one? "
+                                    (buffer-name)))))
+                  (save-excursion
+                    (goto-char (point-max))
+                    (insert ?\n))))
            (or (run-hook-with-args-until-success 'write-contents-hooks)
                (run-hook-with-args-until-success 'local-write-file-hooks)
                (run-hook-with-args-until-success 'write-file-hooks)
@@ -2204,7 +2545,9 @@ After saving the buffer, run `after-save-hook'."
            ;; Now we have saved the current buffer.  Let's make sure
            ;; that buffer-file-coding-system is fixed to what
            ;; actually used for saving by binding it locally.
-           (setq buffer-file-coding-system last-coding-system-used)
+           (if save-buffer-coding-system
+               (setq save-buffer-coding-system last-coding-system-used)
+             (setq buffer-file-coding-system last-coding-system-used))
            (setq buffer-file-number
                  (nthcdr 10 (file-attributes buffer-file-name)))
            (if setmodes
@@ -2224,6 +2567,12 @@ After saving the buffer, run `after-save-hook'."
 ;; but inhibited if one of write-file-hooks returns non-nil.
 ;; It returns a value to store in setmodes.
 (defun basic-save-buffer-1 ()
+  (if save-buffer-coding-system
+      (let ((coding-system-for-write save-buffer-coding-system))
+       (basic-save-buffer-2))
+    (basic-save-buffer-2)))
+
+(defun basic-save-buffer-2 ()
   (let (tempsetmodes setmodes)
     (if (not (file-writable-p buffer-file-name))
        (let ((dir (file-name-directory buffer-file-name)))
@@ -2258,7 +2607,9 @@ After saving the buffer, run `after-save-hook'."
                              (if (and (eq system-type 'ms-dos)
                                       (not (msdos-long-file-names)))
                                  "%s#%d.tm#" ; MSDOS limits files to 8+3
-                               "%s#tmp#%d")
+                               (if (memq system-type '(vax-vms axp-vms))
+                                   "%s$tmp$%d"
+                                 "%s#tmp#%d"))
                              dir i))
              (setq nogood (file-exists-p tempname))
              (setq i (1+ i)))
@@ -2293,11 +2644,14 @@ After saving the buffer, run `after-save-hook'."
                      buffer-file-name nil t buffer-file-truename)))
     setmodes))
 
-(defun save-some-buffers (&optional arg exiting)
+(defun save-some-buffers (&optional arg pred)
   "Save some modified file-visiting buffers.  Asks user about each one.
 Optional argument (the prefix) non-nil means save all with no questions.
-Optional second argument EXITING means ask about certain non-file buffers
- as well as about file buffers."
+Optional second argument PRED determines which buffers are considered:
+If PRED is nil, all the file-visiting buffers are considered.
+If PRED is t, then certain non-file buffers will also be considered.
+If PRED is a zero-argument function, it indicates for each buffer whether
+to consider it or not when called with that buffer current."
   (interactive "P")
   (save-window-excursion
     (let* ((queried nil)
@@ -2309,10 +2663,12 @@ Optional second argument EXITING means ask about certain non-file buffers
                     (not (buffer-base-buffer buffer))
                     (or
                      (buffer-file-name buffer)
-                     (and exiting
+                     (and pred
                           (progn
                             (set-buffer buffer)
                             (and buffer-offer-save (> (buffer-size) 0)))))
+                    (or (not (functionp pred))
+                        (with-current-buffer buffer (funcall pred)))
                     (if arg
                         t
                       (setq queried t)
@@ -2371,7 +2727,9 @@ If visiting file read-only and `view-read-only' is non-nil, enter view mode."
     nil)                               ; do nothing.
    ;; Toggle.
    ((and buffer-read-only view-mode)
-    (View-exit-and-edit))              ; Must leave view mode.
+    (View-exit-and-edit)
+    (make-local-variable 'view-read-only)
+    (setq view-read-only t))           ; Must leave view mode.
    ((and (not buffer-read-only) view-read-only
         (not (eq (get major-mode 'mode-class) 'special)))
     (view-mode-enter))
@@ -2402,15 +2760,18 @@ saying what text to write."
 
 (defun file-newest-backup (filename)
   "Return most recent backup file for FILENAME or nil if no backups exist."
-  (let* ((filename (expand-file-name filename))
+  ;; `make-backup-file-name' will get us the right directory for
+  ;; ordinary or numeric backups.  It might create a directory for
+  ;; backups as a side-effect, according to `backup-directory-alist'.
+  (let* ((filename (file-name-sans-versions
+                   (make-backup-file-name filename)))
         (file (file-name-nondirectory filename))
         (dir  (file-name-directory    filename))
         (comp (file-name-all-completions file dir))
          (newest nil)
          tem)
     (while comp
-      (setq tem (car comp)
-           comp (cdr comp))
+      (setq tem (pop comp))
       (cond ((and (backup-file-name-p tem)
                   (string= (file-name-sans-versions tem) file))
              (setq tem (concat dir tem))
@@ -2473,7 +2834,9 @@ which are the arguments that `revert-buffer' received.")
 (defvar revert-buffer-insert-file-contents-function nil
   "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.")
+and second, t if reading the auto-save file.
+
+The function you specify is responsible for updating (or preserving) point.")
 
 (defvar before-revert-hook nil
   "Normal hook for `revert-buffer' to run before reverting.
@@ -2489,6 +2852,8 @@ hook functions.
 If `revert-buffer-function' is used to override the normal revert
 mechanism, this hook is not used.")
 
+(defvar revert-buffer-internal-hook)
+
 (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.
@@ -2507,7 +2872,8 @@ sake of backward compatibility.  IGNORE-AUTO is optional, defaulting
 to nil.
 
 Optional second argument NOCONFIRM means don't ask for confirmation at
-all.
+all.  (The local variable `revert-without-query', if non-nil, prevents
+confirmation.)
 
 Optional third argument PRESERVE-MODES non-nil means don't alter
 the files modes.  Normally we reinitialize them using `normal-mode'.
@@ -2527,8 +2893,7 @@ non-nil, it is called instead of rereading visited file contents."
   (interactive (list (not current-prefix-arg)))
   (if revert-buffer-function
       (funcall revert-buffer-function ignore-auto noconfirm)
-    (let* ((opoint (point))
-          (auto-save-p (and (not ignore-auto)
+    (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)
@@ -2584,9 +2949,9 @@ non-nil, it is called instead of rereading visited file contents."
                          ;; any code conversion.
                          (if auto-save-p 'no-conversion
                            coding-system-for-read)))
+                    ;; Note that this preserves point in an intelligent way.
                     (insert-file-contents file-name (not auto-save-p)
                                           nil nil t))))
-              (goto-char (min opoint (point-max)))
               ;; Recompute the truename in case changes in symlinks
               ;; have changed the truename.
               (setq buffer-file-truename
@@ -2627,10 +2992,13 @@ non-nil, it is called instead of rereading visited file contents."
             (yes-or-no-p (format "Recover auto save file %s? " file-name)))
           (switch-to-buffer (find-file-noselect file t))
           (let ((buffer-read-only nil)
+                ;; Keep the current buffer-file-coding-system.
+                (coding-system buffer-file-coding-system)
                 ;; Auto-saved file shoule be read without any code conversion.
                 (coding-system-for-read 'no-conversion))
             (erase-buffer)
-            (insert-file-contents file-name nil))
+            (insert-file-contents file-name nil)
+            (set-buffer-file-coding-system coding-system))
           (after-find-file nil nil t))
          (t (error "Recover-file cancelled")))))
 
@@ -2646,13 +3014,16 @@ Then you'll be asked about a number of files to recover."
   (let ((ls-lisp-support-shell-wildcards t))
     (dired (concat auto-save-list-file-prefix "*")
           (concat dired-listing-switches "t")))
-  (goto-char (point-min))
-  (or (looking-at "Move to the session you want to recover,")
-      (let ((inhibit-read-only t))
-       (insert "Move to the session you want to recover,\n"
-               "then type C-c C-c to select it.\n\n"
-               "You can also delete some of these files;\n"
-               "type d on a line to mark that file for deletion.\n\n")))
+  (save-excursion
+    (goto-char (point-min))
+    (or (looking-at " Move to the session you want to recover,")
+       (let ((inhibit-read-only t))
+         ;; Each line starts with a space
+         ;; so that Font Lock mode won't highlight the first character.
+         (insert " Move to the session you want to recover,\n"
+                 " then type C-c C-c to select it.\n\n"
+                 " You can also delete some of these files;\n"
+                 " type d on a line to mark that file for deletion.\n\n"))))
   (use-local-map (nconc (make-sparse-keymap) (current-local-map)))
   (define-key (current-local-map) "\C-c\C-c" 'recover-session-finish))
 
@@ -2665,6 +3036,7 @@ This command is used in the special Dired buffer created by
   (let ((file (dired-get-filename))
        files
        (buffer (get-buffer-create " *recover*")))
+    (dired-unmark 1)
     (dired-do-flagged-delete t)
     (unwind-protect
        (save-excursion
@@ -2752,7 +3124,7 @@ With prefix argument ARG, turn auto-saving on if positive, else off."
   (setq buffer-auto-save-file-name
         (and (if (null arg)
                 (or (not buffer-auto-save-file-name)
-                    ;; If autosave is off because buffer has shrunk,
+                    ;; If auto-save is off because buffer has shrunk,
                     ;; then toggling should turn it on.
                     (< buffer-saved-size 0))
               (or (eq arg t) (listp arg) (and (integerp arg) (> arg 0))))
@@ -2788,17 +3160,29 @@ Does not consider `auto-save-visited-file-name' as that variable is checked
 before calling this function.  You can redefine this for customization.
 See also `auto-save-file-name-p'."
   (if buffer-file-name
-      (if (and (eq system-type 'ms-dos)
-              (not (msdos-long-file-names)))
-         (let ((fn (file-name-nondirectory buffer-file-name)))
-           (string-match "\\`\\([^.]+\\)\\(\\.\\(..?\\)?.?\\|\\)\\'" fn)
-           (concat (file-name-directory buffer-file-name)
-                   "#" (match-string 1 fn) 
-                   "." (match-string 3 fn) "#"))
-       (concat (file-name-directory buffer-file-name)
-               "#"
-               (file-name-nondirectory buffer-file-name)
-               "#"))
+      (let ((list auto-save-file-name-transforms)
+           (filename buffer-file-name)
+           result)
+       ;; Apply user-specified translations
+       ;; to the file name.
+       (while (and list (not result))
+         (if (string-match (car (car list)) filename)
+             (setq result (replace-match (cadr (car list)) t nil
+                                         filename)))
+         (setq list (cdr list)))
+       (if result (setq filename result))
+
+       (if (and (eq system-type 'ms-dos)
+                (not (msdos-long-file-names)))
+           (let ((fn (file-name-nondirectory buffer-file-name)))
+             (string-match "\\`\\([^.]+\\)\\(\\.\\(..?\\)?.?\\|\\)\\'" fn)
+             (concat (file-name-directory buffer-file-name)
+                     "#" (match-string 1 fn) 
+                     "." (match-string 3 fn) "#"))
+         (concat (file-name-directory filename)
+                 "#"
+                 (file-name-nondirectory filename)
+                 "#")))
 
     ;; Deal with buffers that don't have any associated files.  (Mail
     ;; mode tends to create a good number of these.)
@@ -2903,7 +3287,7 @@ by `sh' are supported."
 \f
 (defcustom list-directory-brief-switches
   (if (eq system-type 'vax-vms) "" "-CF")
-  "*Switches for list-directory to pass to `ls' for brief listing,"
+  "*Switches for `list-directory' to pass to `ls' for brief listing."
   :type 'string
   :group 'dired)
 
@@ -2911,10 +3295,53 @@ by `sh' are supported."
   (if (eq system-type 'vax-vms)
       "/PROTECTION/SIZE/DATE/OWNER/WIDTH=(OWNER:10)"
     "-l")
-  "*Switches for list-directory to pass to `ls' for verbose listing,"
+  "*Switches for `list-directory' to pass to `ls' for verbose listing."
   :type 'string
   :group 'dired)
 
+(defun file-expand-wildcards (pattern &optional full)
+  "Expand wildcard pattern PATTERN.
+This returns a list of file names which match the pattern.
+
+If PATTERN is written as an absolute relative file name,
+the values are absolute also.
+
+If PATTERN is written as a relative file name, it is interpreted
+relative to the current default directory, `default-directory'.
+The file names returned are normally also relative to the current
+default directory.  However, if FULL is non-nil, they are absolute."
+  (let* ((nondir (file-name-nondirectory pattern))
+        (dirpart (file-name-directory pattern))
+        ;; A list of all dirs that DIRPART specifies.
+        ;; This can be more than one dir
+        ;; if DIRPART contains wildcards.
+        (dirs (if (and dirpart (string-match "[[*?]" dirpart))
+                  (mapcar 'file-name-as-directory
+                          (file-expand-wildcards (directory-file-name dirpart)))
+                (list dirpart)))
+        contents)
+    (while dirs
+      (when (or (null (car dirs))      ; Possible if DIRPART is not wild.
+               (file-directory-p (directory-file-name (car dirs))))
+       (let ((this-dir-contents
+              ;; Filter out "." and ".."
+              (delq nil
+                    (mapcar #'(lambda (name)
+                                (unless (string-match "\\`\\.\\.?\\'"
+                                                      (file-name-nondirectory name))
+                                  name))
+                            (directory-files (or (car dirs) ".") full
+                                             (wildcard-to-regexp nondir))))))
+         (setq contents
+               (nconc
+                (if (and (car dirs) (not full))
+                    (mapcar (function (lambda (name) (concat (car dirs) name)))
+                            this-dir-contents)
+                  this-dir-contents)
+                contents))))
+      (setq dirs (cdr dirs)))
+    contents))
+
 (defun list-directory (dirname &optional verbose)
   "Display a list of files in or matching DIRNAME, a la `ls'.
 DIRNAME is globbed by the shell if necessary.
@@ -2984,66 +3411,90 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
                 wildcard full-directory-p)
       (if (eq system-type 'vax-vms)
          (vms-read-directory file switches (current-buffer))
-       (or (= 0
-              (if wildcard
-                  ;; Run ls in the directory of the file pattern we asked for.
-                  (let ((default-directory
-                          (if (file-name-absolute-p file)
-                              (file-name-directory file)
-                            (file-name-directory (expand-file-name file))))
-                        (pattern (file-name-nondirectory file))
-                        (beg 0))
-                    ;; Quote some characters that have special meanings in shells;
-                    ;; but don't quote the wildcards--we want them to be special.
-                    ;; We also currently don't quote the quoting characters
-                    ;; in case people want to use them explicitly to quote
-                    ;; wildcard characters.
-                    (while (string-match "[ \t\n;<>&|()#$]" pattern beg)
-                      (setq pattern
-                            (concat (substring pattern 0 (match-beginning 0))
-                                    "\\"
-                                    (substring pattern (match-beginning 0)))
-                            beg (1+ (match-end 0))))
-                    (call-process shell-file-name nil t nil
-                                  "-c" (concat "\\" ;; Disregard shell aliases!
-                                               insert-directory-program
-                                               " -d "
-                                               (if (stringp switches)
-                                                   switches
-                                                 (mapconcat 'identity switches " "))
-                                               " -- "
-                                               (encode-coding-string
-                                                pattern
-                                                file-name-coding-system t))))
-                ;; SunOS 4.1.3, SVr4 and others need the "." to list the
-                ;; directory if FILE is a symbolic link.
-                (apply 'call-process
-                       insert-directory-program nil t nil
-                       (let (list)
-                         (if (listp switches)
-                             (setq list switches)
-                           (if (not (equal switches ""))
-                               (progn
-                                 ;; Split the switches at any spaces
-                                 ;; so we can pass separate options as separate args.
-                                 (while (string-match " " switches)
-                                   (setq list (cons (substring switches 0 (match-beginning 0))
-                                                    list)
-                                         switches (substring switches (match-end 0))))
-                                 (setq list (nreverse (cons switches list))))))
-                         (append list
-                                 ;; Avoid lossage if FILE starts with `-'.
-                                 '("--")
-                                 (list
-                                  (encode-coding-string
-                                   (if full-directory-p
-                                       (concat (file-name-as-directory file) ".")
-                                     file)
-                                   file-name-coding-system t)))))))
-           ;; We get here if ls failed.
-           ;; Access the file to get a suitable error.
-           (access-file file "Reading directory"))))))
-
+       (let* ((coding-system-for-read
+               (and enable-multibyte-characters
+                    (or file-name-coding-system
+                        default-file-name-coding-system)))
+              ;; This is to control encoding the arguments in call-process.
+              (coding-system-for-write coding-system-for-read)
+              (result
+               (if wildcard
+                   ;; Run ls in the directory of the file pattern we asked for.
+                   (let ((default-directory
+                           (if (file-name-absolute-p file)
+                               (file-name-directory file)
+                             (file-name-directory (expand-file-name file))))
+                         (pattern (file-name-nondirectory file))
+                         (beg 0))
+                     ;; Quote some characters that have special meanings in shells;
+                     ;; but don't quote the wildcards--we want them to be special.
+                     ;; We also currently don't quote the quoting characters
+                     ;; in case people want to use them explicitly to quote
+                     ;; wildcard characters.
+                     (while (string-match "[ \t\n;<>&|()#$]" pattern beg)
+                       (setq pattern
+                             (concat (substring pattern 0 (match-beginning 0))
+                                     "\\"
+                                     (substring pattern (match-beginning 0)))
+                             beg (1+ (match-end 0))))
+                     (call-process shell-file-name nil t nil
+                                   "-c" (concat "\\";; Disregard shell aliases!
+                                                insert-directory-program
+                                                " -d "
+                                                (if (stringp switches)
+                                                    switches
+                                                  (mapconcat 'identity switches " "))
+                                                " -- "
+                                                 pattern)))
+                 ;; SunOS 4.1.3, SVr4 and others need the "." to list the
+                 ;; directory if FILE is a symbolic link.
+                 (apply 'call-process
+                         insert-directory-program nil t nil
+                         (let (list)
+                           (if (listp switches)
+                               (setq list switches)
+                             (if (not (equal switches ""))
+                                 (progn
+                                   ;; Split the switches at any spaces
+                                   ;; so we can pass separate options as separate args.
+                                   (while (string-match " " switches)
+                                     (setq list (cons (substring switches 0 (match-beginning 0))
+                                                      list)
+                                           switches (substring switches (match-end 0))))
+                                   (setq list (nreverse (cons switches list))))))
+                           (append list
+                                   ;; Avoid lossage if FILE starts with `-'.
+                                   '("--")
+                                   (progn
+                                     (if (string-match "\\`~" file)
+                                         (setq file (expand-file-name file)))
+                                     (list
+                                      (if full-directory-p
+                                          (concat (file-name-as-directory file) ".")
+                                        file)))))))))
+         (if (/= result 0)
+             ;; We get here if ls failed.
+             ;; Access the file to get a suitable error.
+             (access-file file "Reading directory")
+           ;; Replace "total" with "used", to avoid confusion.
+           ;; Add in the amount of free space.
+           (save-excursion
+             (goto-char (point-min))
+             (when (re-search-forward "^total" nil t)
+               (replace-match "used")
+               (end-of-line)
+               (let (available)
+                 (with-temp-buffer
+                   (call-process "df" nil t nil ".")
+                   (goto-char (point-min))
+                   (forward-line 1)
+                   (skip-chars-forward "^ \t")
+                   (forward-word 3)
+                   (let ((end (point)))
+                     (forward-word -1)
+                     (setq available (buffer-substring (point) end))))
+                 (insert " available " available))))))))))
+                   
 (defvar kill-emacs-query-functions nil
   "Functions to call with no arguments to query about killing Emacs.
 If any of these functions returns nil, killing Emacs is cancelled.
@@ -3073,12 +3524,13 @@ With prefix arg, silently save all file-visiting buffers, then kill."
                    (setq active t))
               (setq processes (cdr processes)))
             (or (not active)
+                (list-processes)
                 (yes-or-no-p "Active processes exist; kill them and exit anyway? "))))
        ;; Query the user for other things, perhaps.
        (run-hook-with-args-until-failure 'kill-emacs-query-functions)
        (kill-emacs)))
 \f
-;; We use /: as a prefix to "quote" a file name 
+;; We use /: as a prefix to "quote" a file name
 ;; so that magic file name handlers will not apply to it.
 
 (setq file-name-handler-alist
@@ -3095,7 +3547,7 @@ With prefix arg, silently save all file-visiting buffers, then kill."
        (default-directory
          (if (eq operation 'insert-directory)
              (directory-file-name
-              (expand-file-name 
+              (expand-file-name
                (unhandled-file-name-directory default-directory)))
            default-directory))
        ;; Get a list of the indices of the args which are file names.