entered into RCS
[bpt/emacs.git] / lisp / files.el
index 9aea763..31ce9ac 100644 (file)
@@ -1,11 +1,14 @@
-;; File input and output commands for Emacs
-;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
+;;; files.el --- file input and output commands for Emacs
+
+;; Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc.
+
+;; Maintainer: FSF
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 1, or (at your option)
+;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -17,6 +20,8 @@
 ;; along with GNU Emacs; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 
+;;; Code:
+
 (defconst delete-auto-save-files t
   "*Non-nil means delete a buffer's auto-save file when the buffer is saved.")
 
@@ -87,6 +92,30 @@ even if the buffer is not visiting a file.
 Automatically local in all buffers.")
 (make-variable-buffer-local 'buffer-offer-save)
 
+(defconst find-file-existing-other-name nil
+  "*Non-nil means find a file under alternative names, in existing buffers.
+This means if any existing buffer is visiting the file you want
+under another name, you get the existing buffer instead of a new buffer.")
+
+(defconst find-file-visit-truename nil
+  "*Non-nil means visit a file under its truename.
+The truename of a file is found by chasing all links
+both at the file level and at the levels of the containing directories.")
+
+(defvar buffer-file-truename nil
+  "The truename of the file visited in the current buffer.
+This variable is automatically local in all buffers, when non-nil.")
+(make-variable-buffer-local 'buffer-file-truename)
+(put 'buffer-file-truename 'permanent-local t)
+
+(defvar buffer-file-number nil
+  "The device number and file number of the file visited in the current buffer.
+The value is a list of the form (FILENUM DEVNUM).
+This pair of numbers uniquely identifies the file.
+If the buffer is visiting a new file, the value is nil.")
+(make-variable-buffer-local 'buffer-file-number)
+(put 'buffer-file-number 'permanent-local t)
+
 (defconst file-precious-flag nil
   "*Non-nil means protect against I/O errors while saving files.
 Some modes set this non-nil in particular buffers.")
@@ -101,8 +130,8 @@ never means do not make them.")
   "*When cleaning directory, number of versions to keep.")
 
 (defvar trim-versions-without-asking nil
-  "*If true, deletes excess backup versions silently.
-Otherwise asks confirmation.")
+  "*If t, deletes excess backup versions silently.
+If nil, asks confirmation.  Any other value prevents any trimming.")
 
 (defvar kept-old-versions 2
   "*Number of oldest versions to keep when a new numbered backup is made.")
@@ -147,7 +176,19 @@ functions are called.")
 (defvar write-file-hooks nil
   "List of functions to be called before writing out a buffer to a file.
 If one of them returns non-nil, the file is considered already written
-and the rest are not called.")
+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.
+See also `write-contents-hooks'.")
+
+(defvar write-contents-hooks nil
+  "List of functions to be called before writing out a buffer to a file.
+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 buffer's contents,
+not to the particular visited file; thus, `set-visited-file-name' does
+not clear this variable, but changing the major mode does clear it.
+See also `write-file-hooks'.")
 
 (defconst enable-local-variables t
   "*Control use of local-variables lists in files you visit.
@@ -158,11 +199,14 @@ nil means they are ignored; anything else means query.
 The command \\[normal-mode] always obeys local-variables lists
 and ignores this variable.")
 
-(defconst ignore-local-eval nil
-  "*Non-nil means ignore the \"variable\" `eval' in a file's local variables.
-This applies when the local-variables list is scanned automatically
-after you find a file.  If you explicitly request such a scan with
-\\[normal-mode], there is no query, regardless of this variable.")
+(defconst 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.
+A value of t means obey `eval' variables;
+nil means ignore them; anything else means query.
+
+The command \\[normal-mode] always obeys local-variables lists
+and ignores this variable.")
 
 ;; Avoid losing in versions where CLASH_DETECTION is disabled.
 (or (fboundp 'lock-buffer)
@@ -186,7 +230,10 @@ after you find a file.  If you explicitly request such a scan with
     (if (file-executable-p dir)
        (setq default-directory dir)
       (error "Cannot cd to %s:  Permission denied" dir)))
-  (pwd))
+  ;; We used to call pwd at this point.  That's not terribly helpful
+  ;; when we're invoking cd interactively, and the new cmushell-based
+  ;; shell has its own (better) facilities for this.
+)
 
 (defun load-file (file)
   "Load the Lisp file named FILE."
@@ -198,6 +245,47 @@ after you find a file.  If you explicitly request such a scan with
 This is an interface to the function `load'."
   (interactive "sLoad library: ")
   (load library))
+
+;; OTHER is the other file to be compared.
+(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."
+  (let ((handler (find-file-name-handler file)))
+    (if handler
+       (funcall handler 'file-local-copy file)
+      nil)))
+
+(defun file-truename (filename)
+  "Return the truename of FILENAME, which should be absolute.
+The truename of a file name is found by chasing symbolic links
+both at the level of the file and at the level of the directories
+containing it, until no links are left at any level."
+  (if (string= filename "~")
+      (setq filename (expand-file-name filename)))
+  (let ((handler (find-file-name-handler filename)))
+    ;; For file name that has a special handler, call handler.
+    ;; This is so that ange-ftp can save time by doing a no-op.
+    (if handler
+       (funcall handler 'file-truename filename)
+      (let ((dir (file-name-directory filename))
+           target dirfile)
+       ;; Get the truename of the directory.
+       (setq dirfile (directory-file-name dir))
+       ;; If these are equal, we have the (or a) root directory.
+       (or (string= dir dirfile)
+           (setq dir (file-name-as-directory (file-truename dirfile))))
+       ;; Put it back on the file name.
+       (setq filename (concat dir (file-name-nondirectory filename)))
+       ;; Is the file name the name of a link?
+       (setq target (file-symlink-p filename))
+       (if target
+           ;; Yes => chase that link, then start all over
+           ;; since the link may point to a directory name that uses links.
+           (file-truename (expand-file-name target dir))
+         ;; No, we are done!
+         filename)))))
+
 \f
 (defun switch-to-buffer-other-window (buffer)
   "Select buffer BUFFER in another window."
@@ -205,6 +293,12 @@ This is an interface to the function `load'."
   (let ((pop-up-windows t))
     (pop-to-buffer buffer t)))
 
+(defun switch-to-buffer-other-frame (buffer)
+  "Switch to buffer BUFFER in another frame."
+  (interactive "BSwitch to buffer in other frame: ")
+  (let ((pop-up-frames t))
+    (pop-to-buffer buffer)))
+
 (defun find-file (filename)
   "Edit file FILENAME.
 Switch to a buffer visiting file FILENAME,
@@ -219,6 +313,13 @@ See the function `display-buffer'."
   (interactive "FFind file in other window: ")
   (switch-to-buffer-other-window (find-file-noselect filename)))
 
+(defun find-file-other-frame (filename)
+  "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)))
+
 (defun find-file-read-only (filename)
   "Edit file FILENAME but don't allow changes.
 Like \\[find-file] but marks buffer as read-only.
@@ -235,6 +336,14 @@ Use \\[toggle-read-only] to permit editing."
   (find-file filename)
   (setq buffer-read-only t))
 
+(defun find-file-read-only-other-frame (filename)
+  "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)
+  (setq buffer-read-only t))
+
 (defun find-alternate-file (filename)
   "Find file FILENAME, select its buffer, kill previous buffer.
 If the current buffer now contains an empty file that you just visited
@@ -246,7 +355,8 @@ If the current buffer now contains an empty file that you just visited
      (and file
          (setq file-name (file-name-nondirectory file)
                file-dir (file-name-directory file)))
-     (list (read-file-name "Find alternate file: " file-dir nil nil file-name))))
+     (list (read-file-name
+           "Find alternate file: " file-dir nil nil file-name))))
   (and (buffer-modified-p)
        ;; (not buffer-read-only)
        (not (yes-or-no-p (format "Buffer %s is modified; kill anyway? "
@@ -277,30 +387,100 @@ otherwise a string <2> or <3> or ... is appended to get an unused name."
        (setq lastname filename))
     (generate-new-buffer lastname)))
 
-(defun find-file-noselect (filename &optional nowarn)
-  "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."
-  (setq filename (expand-file-name filename))
+(defun generate-new-buffer (name)
+  "Create and return a buffer with a name based on NAME.
+Choose the buffer's name using `generate-new-buffer-name'."
+  (get-buffer-create (generate-new-buffer-name name)))
+
+(defconst automount-dir-prefix "^/tmp_mnt/"
+  "Regexp to match the automounter prefix in a directory name.")
+
+(defvar abbreviated-home-dir nil
+  "The the user's homedir abbreviated according to `directory-abbrev-list'.")
+
+(defun abbreviate-file-name (filename)
+  "Return a version of FILENAME shortened using `directory-abbrev-alist'.
+This also substitutes \"~\" for the user's home directory.
+Type \\[describe-variable] directory-abbrev-alist RET for more information."
   ;; Get rid of the prefixes added by the automounter.
-  (if (and (string-match "^/tmp_mnt/" filename)
+  (if (and (string-match automount-dir-prefix filename)
           (file-exists-p (file-name-directory
                           (substring filename (1- (match-end 0))))))
       (setq filename (substring filename (1- (match-end 0)))))
-  ;; Perform any appropriate abbreviations specified in directory-abbrev-alist.
   (let ((tail directory-abbrev-alist))
+    ;; If any elt of directory-abbrev-alist matches this name,
+    ;; abbreviate accordingly.
     (while tail
       (if (string-match (car (car tail)) filename)
          (setq filename
                (concat (cdr (car tail)) (substring filename (match-end 0)))))
-      (setq tail (cdr tail))))
+      (setq tail (cdr tail)))
+    ;; Compute and save the abbreviated homedir name.
+    ;; We defer computing this until the first time it's needed, to
+    ;; give time for directory-abbrev-alist to be set properly.
+    (or abbreviated-home-dir
+       (setq abbreviated-home-dir
+             (let ((abbreviated-home-dir "$foo"))
+               (concat "^" (abbreviate-file-name (expand-file-name "~"))))))
+    ;; If FILENAME starts with the abbreviated homedir,
+    ;; make it start with `~' instead.
+    (if (string-match abbreviated-home-dir filename)
+       (setq filename
+             (concat "~" (substring filename (match-end 0)))))
+    filename))
+
+(defun find-file-noselect (filename &optional nowarn)
+  "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."
+  (setq filename
+       (abbreviate-file-name
+        (expand-file-name filename)))
   (if (file-directory-p filename)
       (if find-file-run-dired
          (dired-noselect filename)
        (error "%s is a directory." filename))
-    (let ((buf (get-file-buffer filename))
-         error)
+    (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.
+          (same-truename
+           (or buf ; Shortcut
+               (let (found
+                     (list (buffer-list)))
+                 (while (and (not found) list)
+                   (save-excursion
+                     (set-buffer (car list))
+                     (if (string= buffer-file-truename truename)
+                       (setq found (car list))))
+                   (setq list (cdr list)))
+                 found)))
+          (same-number
+           (or buf ; Shortcut
+               (and number
+                    (let (found
+                          (list (buffer-list)))
+                      (while (and (not found) list)
+                        (save-excursion
+                          (set-buffer (car list))
+                          (if (equal buffer-file-number number)
+                            (setq found (car list))))
+                        (setq list (cdr list)))
+                      found))))
+          error)
+      ;; Let user know if there is a buffer with the same truename.
+      (if (and (not buf) same-truename (not nowarn))
+         (message "%s and %s are the same file (%s)"
+                  filename (buffer-file-name same-truename)
+                  truename)
+       (if (and (not buf) same-number (not nowarn))
+         (message "%s and %s are the same file"
+                  filename (buffer-file-name same-number))))
+
+      ;; Optionally also find that buffer.
+      (if (or find-file-existing-other-name find-file-visit-truename)
+         (setq buf (or same-truename same-number)))
       (if buf
          (or nowarn
              (verify-visited-file-modtime buf)
@@ -316,12 +496,13 @@ The buffer is not selected, just returned to the caller."
                       (set-buffer buf)
                       (revert-buffer t t)))))
        (save-excursion
-         (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))))
+;;; 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))))
          (setq buf (create-file-buffer filename))
          (set-buffer buf)
          (erase-buffer)
@@ -334,6 +515,10 @@ The buffer is not selected, just returned to the caller."
               (while (and hooks
                           (not (funcall (car hooks))))
                 (setq hooks (cdr hooks))))))
+         ;; Find the file's truename, and maybe use that as visited name.
+         (setq buffer-file-truename (abbreviate-file-name truename))
+         (setq buffer-file-number number) 
+         (if find-file-visit-truename (setq filename 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
@@ -345,12 +530,13 @@ The buffer is not selected, just returned to the caller."
          (after-find-file error (not nowarn))))
       buf)))
 \f
-(defun after-find-file (&optional error warn)
+(defun after-find-file (&optional error warn noauto)
   "Called after finding a file and by the default revert function.
 Sets buffer mode, parses local variables.
-Optional args ERROR and WARN: ERROR non-nil means there was an
+Optional args ERROR, WARN, and NOAUTO: ERROR non-nil means there was an
 error in reading the file.  WARN non-nil means warn if there
 exists an auto-save file more recent than the visited file.
+NOAUTO means don't mess with auto-save mode.
 Finishes by calling the functions in `find-file-hooks'."
   (setq buffer-read-only (not (file-writable-p buffer-file-name)))
   (if noninteractive
@@ -372,13 +558,18 @@ Finishes by calling the functions in `find-file-hooks'."
                   "Note: file is write protected")
                  ((file-attributes (directory-file-name default-directory))
                   "File not found and directory write-protected")
+                 ((file-exists-p (file-name-directory buffer-file-name))
+                  (setq buffer-read-only nil))
                  (t
-                  "File not found and directory doesn't exist"))))
+                  (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")))))
       (if msg
          (progn
            (message msg)
            (or not-serious (sit-for 1 nil t)))))
-    (if auto-save-default
+    (if (and auto-save-default (not noauto))
        (auto-save-mode t)))
   (normal-mode t)
   (mapcar 'funcall find-file-hooks))
@@ -400,26 +591,90 @@ run `normal-mode' explicitly."
     (error (message "File mode specification error: %s"
                    (prin1-to-string err))))
   (condition-case err
-      (hack-local-variables (not find-file))
+      (let ((enable-local-variables (or (not find-file)
+                                       enable-local-variables)))
+       (hack-local-variables))
     (error (message "File local-variables error: %s"
                    (prin1-to-string err)))))
 
-;(defvar auto-mode-alist ...) now in loaddefs.el
+(defvar auto-mode-alist (mapcar 'purecopy
+                               '(("\\.text\\'" . text-mode)
+                                 ("\\.c\\'" . c-mode)
+                                 ("\\.h\\'" . c-mode)
+                                 ("\\.tex\\'" . TeX-mode)
+                                 ("\\.ltx\\'" . LaTeX-mode)
+                                 ("\\.el\\'" . emacs-lisp-mode)
+                                 ("\\.mm\\'" . nroff-mode)
+                                 ("\\.me\\'" . nroff-mode)
+                                 ("\\.scm\\'" . scheme-mode)
+                                 ("\\.l\\'" . lisp-mode)
+                                 ("\\.lisp\\'" . lisp-mode)
+                                 ("\\.f\\'" . fortran-mode)
+                                 ("\\.for\\'" . fortran-mode)
+                                 ("\\.mss\\'" . scribe-mode)
+                                 ("\\.pl\\'" . prolog-mode)
+                                 ("\\.cc\\'" . c++-mode)
+                                 ("\\.C\\'" . c++-mode)
+;;; Less common extensions come here
+;;; so more common ones above are found faster.
+                                 ("\\.s\\'" . asm-mode)
+                                 ("ChangeLog\\'" . change-log-mode)
+                                 ("ChangeLog.[0-9]+\\'" . change-log-mode)
+                                 ("\\$CHANGE_LOG\\$\\.TXT" . change-log-mode)
+;; The following should come after the ChangeLog pattern
+;; for the sake of ChangeLog.1, etc.
+                                 ("\\.[12345678]\\'" . nroff-mode)
+                                 ("\\.TeX\\'" . TeX-mode)
+                                 ("\\.sty\\'" . LaTeX-mode)
+                                 ("\\.bbl\\'" . LaTeX-mode)
+                                 ("\\.bib\\'" . bibtex-mode)
+                                 ("\\.article\\'" . text-mode)
+                                 ("\\.letter\\'" . text-mode)
+                                 ("\\.texinfo\\'" . texinfo-mode)
+                                 ("\\.texi\\'" . texinfo-mode)
+                                 ("\\.lsp\\'" . lisp-mode)
+                                 ("\\.awk\\'" . awk-mode)
+                                 ("\\.prolog\\'" . prolog-mode)
+                                 ;; Mailer puts message to be edited in
+                                 ;; /tmp/Re.... or Message
+                                 ("^/tmp/Re" . text-mode)
+                                 ("/Message[0-9]*\\'" . text-mode)
+                                 ;; some news reader is reported to use this
+                                 ("^/tmp/fol/" . text-mode)
+                                 ("\\.y\\'" . c-mode)
+                                 ("\\.oak\\'" . scheme-mode)
+                                 ("\\.scm.[0-9]*\\'" . scheme-mode)
+                                 ;; .emacs following a directory delimiter
+                                 ;; in either Unix or VMS syntax.
+                                 ("[]>:/]\\..*emacs\\'" . emacs-lisp-mode)
+                                 ("\\.ml\\'" . lisp-mode)))
+  "\
+Alist of filename patterns vs corresponding major mode functions.
+Each element looks like (REGEXP . FUNCTION).
+Visiting a file whose name matches REGEXP causes FUNCTION to be called.")
+
 (defun set-auto-mode ()
   "Select major mode appropriate for current buffer.
-May base decision on visited file name (see variable `auto-mode-alist')
-or on buffer contents (-*- line or local variables spec), but does not look
-for the \"mode:\" local variable.  For that, use `hack-local-variables'."
+This checks for a -*- mode tag in the buffer's text, or
+compares the filename against the entries in auto-mode-alist.  It does
+not check for the \"mode:\" local variable in the Local Variables
+section of the file; for that, use `hack-local-variables'.
+
+If `enable-local-variables' is nil, this function does not check for a
+-*- mode tag."
   ;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*-
   (let (beg end mode)
     (save-excursion
       (goto-char (point-min))
       (skip-chars-forward " \t\n")
-      (if (and (search-forward "-*-" (save-excursion (end-of-line) (point)) t)
+      (if (and enable-local-variables
+              (search-forward "-*-" (save-excursion (end-of-line) (point)) t)
               (progn
                 (skip-chars-forward " \t")
                 (setq beg (point))
-                (search-forward "-*-" (save-excursion (end-of-line) (point)) t))
+                (search-forward "-*-"
+                                (save-excursion (end-of-line) (point))
+                                t))
               (progn
                 (forward-char -3)
                 (skip-chars-backward " \t")
@@ -452,16 +707,79 @@ for the \"mode:\" local variable.  For that, use `hack-local-variables'."
              (setq alist (cdr alist)))))))
     (if mode (funcall mode))))
 
-(defun hack-local-variables (&optional force)
-  "Parse (and bind or evaluate as appropriate) any local variables
-for current buffer."
+(defun hack-local-variables-prop-line ()
+  ;; Set local variables specified in the -*- line.
+  ;; Returns t if mode was set.
+  (save-excursion
+    (goto-char (point-min))
+    (skip-chars-forward " \t\n\r")
+    (let ((result '())
+         (end (save-excursion (end-of-line) (point)))
+         mode-p)
+      ;; Parse the -*- line into the `result' alist.
+      (cond ((not (search-forward "-*-" end t))
+            ;; doesn't have one.
+            nil)
+           ((looking-at "[ \t]*\\([^ \t\n\r:;]+\\)\\([ \t]*-\\*-\\)")
+            ;; Simple form: "-*- MODENAME -*-".
+            (setq result
+              (list (cons 'mode
+                          (intern (buffer-substring
+                                   (match-beginning 1)
+                                   (match-end 1)))))))
+           (t
+            ;; Hairy form: '-*-' [ <variable> ':' <value> ';' ]* '-*-'
+            ;; (last ";" is optional).
+            (save-excursion
+              (if (search-forward "-*-" end t)
+                  (setq end (- (point) 3))
+                (error "-*- not terminated before end of line")))
+            (while (< (point) end)
+              (or (looking-at "[ \t]*\\([^ \t\n:]+\\)[ \t]*:[ \t]*")
+                  (error "malformed -*- line"))
+              (goto-char (match-end 0))
+              (let ((key (intern (downcase (buffer-substring
+                                            (match-beginning 1)
+                                            (match-end 1)))))
+                    (val (save-restriction
+                           (narrow-to-region (point) end)
+                           (read (current-buffer)))))
+                (setq result (cons (cons key val) result))
+                (skip-chars-forward " \t;")))
+            (setq result (nreverse result))))
+
+      ;; Mode is magic.
+      (let (mode)
+       (while (setq mode (assq 'mode result))
+         (setq mode-p t result (delq mode result))
+         (funcall (intern (concat (downcase (symbol-name (cdr mode)))
+                                  "-mode")))))
+      
+      (if (and result
+              (or (eq enable-local-variables t)
+                  (and enable-local-variables
+                       (save-window-excursion
+                         (switch-to-buffer (current-buffer))
+                         (y-or-n-p (format "Set local variables as specified in -*- line of %s? "
+                                           (file-name-nondirectory buffer-file-name)))))))
+         (while result
+           (let ((key (car (car result)))
+                 (val (cdr (car result))))
+             ;; 'mode has already been removed from this list.
+             (hack-one-local-variable key val))
+           (setq result (cdr result))))
+      mode-p)))
+
+(defun hack-local-variables ()
+  "Parse and put into effect this buffer's local variables spec."
+  (hack-local-variables-prop-line)
   ;; Look for "Local variables:" line in last page.
   (save-excursion
     (goto-char (point-max))
     (search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
     (if (let ((case-fold-search t))
          (and (search-forward "Local Variables:" nil t)
-              (or force (eq enable-local-variables t)
+              (or (eq enable-local-variables t)
                   (and enable-local-variables
                        (save-window-excursion
                          (switch-to-buffer (current-buffer))
@@ -471,7 +789,8 @@ for current buffer."
                          (y-or-n-p (format "Set local variables as specified at end of %s? "
                                            (file-name-nondirectory buffer-file-name))))))))
        (let ((continue t)
-             prefix prefixlen suffix beg)
+             prefix prefixlen suffix beg
+             (enable-local-eval enable-local-eval))
          ;; The prefix is what comes before "local variables:" in its line.
          ;; The suffix is what comes after "local variables:" in its line.
          (skip-chars-forward " \t")
@@ -483,6 +802,7 @@ for current buffer."
              (setq prefix
                    (buffer-substring (point)
                                      (progn (beginning-of-line) (point)))))
+
          (if prefix (setq prefixlen (length prefix)
                           prefix (regexp-quote prefix)))
          (if suffix (setq suffix (concat (regexp-quote suffix) "$")))
@@ -516,16 +836,39 @@ for current buffer."
                (or (if suffix (looking-at suffix) (eolp))
                    (error "Local variables entry is terminated incorrectly"))
                ;; Set the variable.  "Variables" mode and eval are funny.
-               (cond ((eq var 'mode)
-                      (funcall (intern (concat (downcase (symbol-name val))
-                                               "-mode"))))
-                     ((eq var 'eval)
-                      (if (or (and ignore-local-eval (not force))
-                              (string= (user-login-name) "root"))
-                          (message "Ignoring `eval:' in file's local variables")
-                        (save-excursion (eval val))))
-                     (t (make-local-variable var)
-                        (set var val))))))))))
+               (hack-one-local-variable var val))))))))
+
+(defconst ignored-local-variables
+  '(enable-local-eval)
+  "Variables to be ignored in a file's local variable spec.")
+
+;; "Set" one variable in a local variables spec.
+;; A few variable names are treated specially.
+(defun hack-one-local-variable (var val)
+  (cond ((eq var 'mode)
+        (funcall (intern (concat (downcase (symbol-name val))
+                                 "-mode"))))
+       ((memq var ignored-local-variables)
+        nil)
+       ;; "Setting" eval means either eval it or do nothing.
+       ((eq var 'eval)
+        (if (and (not (string= (user-login-name) "root"))
+                 (or (eq enable-local-eval t)
+                     (and enable-local-eval
+                          (save-window-excursion
+                            (switch-to-buffer (current-buffer))
+                            (save-excursion
+                              (beginning-of-line)
+                              (set-window-start (selected-window) (point)))
+                            (setq enable-local-eval
+                                  (y-or-n-p (format "Process `eval' local variable in file %s? "
+                                                    (file-name-nondirectory buffer-file-name))))))))
+            (save-excursion (eval val))
+          (message "Ignoring `eval:' in file's local variables")))
+       ;; Ordinary variable, really set it.
+       (t (make-local-variable var)
+          (set var val))))
+
 \f
 (defun set-visited-file-name (filename)
   "Change name of file visited in current buffer to FILENAME.
@@ -546,25 +889,23 @@ if you wish to pass an empty string as the argument."
        (unlock-buffer)))
   (setq buffer-file-name filename)
   (if filename                         ; make buffer name reflect filename.
-      (let ((new-name (file-name-nondirectory buffer-file-name))
-           (old-name (buffer-name (current-buffer))))
+      (let ((new-name (file-name-nondirectory buffer-file-name)))
        (if (string= new-name "")
            (error "Empty file name"))
        (if (eq system-type 'vax-vms)
            (setq new-name (downcase new-name)))
        (setq default-directory (file-name-directory buffer-file-name))
-       (and (get-buffer new-name)
-            (setq new-name
-                  (buffer-name (create-file-buffer buffer-file-name)))
-            (kill-buffer new-name))
-       (rename-buffer new-name)
-       (if (string= (prog1 (setq new-name (buffer-name (create-file-buffer
-                                                        buffer-file-name)))
-                      (kill-buffer new-name))
-                    old-name)
-           (rename-buffer old-name))))
+       (rename-buffer new-name t)))
   (setq buffer-backed-up nil)
   (clear-visited-file-modtime)
+  (if filename
+      (progn
+       (setq buffer-file-truename
+             (abbreviate-file-name (file-truename buffer-file-name)))
+       (if find-file-visit-truename
+           (setq buffer-file-name buffer-file-truename))
+       (setq buffer-file-number (nth 10 (file-attributes buffer-file-name))))
+    (setq buffer-file-truename nil buffer-file-number nil))
   ;; write-file-hooks is normally used for things like ftp-find-file
   ;; that visit things that are not local files as if they were files.
   ;; Changing to visit an ordinary local file instead should flush the hook.
@@ -579,7 +920,14 @@ if you wish to pass an empty string as the argument."
         (setq backup-inhibited t)))
   ;; If auto-save was not already on, turn it on if appropriate.
   (if (not buffer-auto-save-file-name)
-      (auto-save-mode (and buffer-file-name auto-save-default)))
+      (auto-save-mode (and buffer-file-name auto-save-default))
+    ;; If auto save is on, start using a new name.
+    ;; We deliberately don't rename or delete the old auto save
+    ;; for the old visited file name.  This is because perhaps
+    ;; the user wants to save the new state and then compare with the
+    ;; previous state from the auto save file.
+    (setq buffer-auto-save-file-name
+         (make-auto-save-file-name)))
   (if buffer-file-name
       (set-buffer-modified-p t)))
 
@@ -632,6 +980,7 @@ the modes of the new file to agree with the old modes."
                   ;; ask the user to confirm now, before doing anything.
                   ;; But don't actually delete til later.
                   (and targets
+                       (or (eq trim-versions-without-asking t) (eq trim-versions-without-asking nil))
                        (or trim-versions-without-asking
                            (y-or-n-p (format "Delete excess backup versions of %s? "
                                              real-file-name))))))
@@ -646,11 +995,16 @@ the modes of the new file to agree with the old modes."
                               (let ((attr (file-attributes real-file-name)))
                                 (or (nth 9 attr)
                                     (/= (nth 2 attr) (user-uid))))))
-                     (copy-file real-file-name backupname t t)
-; rename-file should delete old backup.
-;                  (condition-case ()
-;                      (delete-file backupname)
-;                    (file-error nil))
+                     (condition-case ()
+                         (copy-file real-file-name backupname t t)
+                       (file-error
+                        ;; If copying fails because file BACKUPNAME
+                        ;; is not writable, delete that file and try again.
+                        (if (and (file-exists-p backupname)
+                                 (not (file-writable-p backupname)))
+                            (delete-file backupname))
+                        (copy-file real-file-name backupname t t)))
+                   ;; rename-file should delete old backup.
                    (rename-file real-file-name backupname t)
                    (setq setmodes (file-modes backupname)))
                (file-error
@@ -658,7 +1012,15 @@ the modes of the new file to agree with the old modes."
                 (setq backupname (expand-file-name "~/%backup%~"))
                 (message "Cannot write backup file; backing up in ~/%%backup%%~")
                 (sleep-for 1)
-                (copy-file real-file-name backupname t t)))
+                (condition-case ()
+                    (copy-file real-file-name backupname t t)
+                  (file-error
+                   ;; If copying fails because file BACKUPNAME
+                   ;; is not writable, delete that file and try again.
+                   (if (and (file-exists-p backupname)
+                            (not (file-writable-p backupname)))
+                       (delete-file backupname))
+                   (copy-file real-file-name backupname t t)))))
              (setq buffer-backed-up t)
              ;; Now delete the old versions, if desired.
              (if delete-old-versions
@@ -670,25 +1032,32 @@ the modes of the new file to agree with the old modes."
              setmodes)
        (file-error nil)))))
 
-(defun file-name-sans-versions (name)
+(defun file-name-sans-versions (name &optional keep-backup-version)
   "Return FILENAME sans backup versions or strings.
 This is a separate procedure so your site-init or startup file can
-redefine it."
-  (substring name 0
-             (if (eq system-type 'vax-vms)
-                ;; VMS version number is (a) semicolon, optional
-                ;; sign, zero or more digits or (b) period, option
-                ;; sign, zero or more digits, provided this is the
-                ;; second period encountered outside of the
-                ;; device/directory part of the file name.
-                 (or (string-match ";[---+]?[0-9]*\\'" name)
-                     (if (string-match "\\.[^]>:]*\\(\\.[---+]?[0-9]*\\)\\'"
-                                       name)
-                         (match-beginning 1))
-                     (length name))
-               (or (string-match "\\.~[0-9]+~\\'" name)
-                   (string-match "~\\'" name)
-                   (length name)))))
+redefine it.
+If the optional argument KEEP-BACKUP-VERSION is non-nil,
+we do not remove backup version numbers, only true file version numbers."
+  (let ((handler (find-file-name-handler name)))
+    (if handler
+       (funcall handler 'file-name-sans-versions name keep-backup-version)
+      (substring name 0
+                (if (eq system-type 'vax-vms)
+                    ;; VMS version number is (a) semicolon, optional
+                    ;; sign, zero or more digits or (b) period, option
+                    ;; sign, zero or more digits, provided this is the
+                    ;; second period encountered outside of the
+                    ;; device/directory part of the file name.
+                    (or (string-match ";[---+]?[0-9]*\\'" name)
+                        (if (string-match "\\.[^]>:]*\\(\\.[---+]?[0-9]*\\)\\'"
+                                          name)
+                            (match-beginning 1))
+                        (length name))
+                  (if keep-backup-version
+                      (length name)
+                    (or (string-match "\\.~[0-9]+~\\'" name)
+                        (string-match "~\\'" name)
+                        (length name))))))))
 
 (defun make-backup-file-name (file)
   "Create the non-numeric backup file name for FILE.
@@ -701,6 +1070,19 @@ This is a separate function so you can redefine it for customization.
 You may need to redefine `file-name-sans-versions' as well."
   (string-match "~$" file))
 
+;; 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.
+(defun backup-extract-version (fn)
+  "Given the name of a numeric backup file, return the backup number.
+Uses the free variable `bv-length', whose value should be
+the index in the name where the version number begins."
+  (if (and (string-match "[0-9]+~$" fn bv-length)
+          (= (match-beginning 0) bv-length))
+      (string-to-int (substring fn bv-length -1))
+      0))
+
 ;; 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)
@@ -714,9 +1096,11 @@ Value is a list whose car is the name for the backup file
           (possibilities (file-name-all-completions
                           base-versions
                           (file-name-directory fn)))
-          (versions (sort (mapcar 'backup-extract-version possibilities)
+          (versions (sort (mapcar
+                           (function backup-extract-version)
+                           possibilities)
                           '<))
-          (high-water-mark (apply 'max (cons 0 versions)))
+          (high-water-mark (apply 'max 0 versions))
           (deserve-versions-p
            (or version-control
                (> high-water-mark 0)))
@@ -732,15 +1116,27 @@ Value is a list whose car is the name for the backup file
                            (rplacd (nthcdr (1- number-to-delete) v) ())
                            v))))))))
 
-(defun backup-extract-version (fn)
-  (if (and (string-match "[0-9]+~$" fn bv-length)
-          (= (match-beginning 0) bv-length))
-      (string-to-int (substring fn bv-length -1))
-      0))
-
 (defun file-nlinks (filename)
   "Return number of names file FILENAME has."
   (car (cdr (file-attributes filename))))
+
+(defun file-relative-name-1 (directory)
+  (cond ((string= directory "/")
+        filename)
+       ((string-match (concat "^" (regexp-quote directory))
+                      filename)
+        (substring filename (match-end 0)))
+       (t
+        (file-relative-name-1
+         (file-name-directory (substring directory 0 -1))))))
+
+(defun file-relative-name (filename &optional directory)
+  "Convert FILENAME to be relative to DIRECTORY (default: default-directory)."
+  (setq filename (expand-file-name filename)
+       directory (file-name-as-directory (if directory
+                                             (expand-file-name directory)
+                                             default-directory)))
+  (file-relative-name-1 directory))
 \f
 (defun save-buffer (&optional args)
   "Save current buffer in visited file if modified.  Versions described below.
@@ -831,7 +1227,7 @@ the last real save, but optional arg FORCE non-nil means delete anyway."
               (save-excursion
                 (goto-char (point-max))
                 (insert ?\n)))
-         (let ((hooks write-file-hooks)
+         (let ((hooks (append write-contents-hooks write-file-hooks))
                (done nil))
            (while (and hooks
                        (not (setq done (funcall (car hooks)))))
@@ -853,40 +1249,28 @@ the last real save, but optional arg FORCE non-nil means delete anyway."
                   (or buffer-backed-up
                       (setq setmodes (backup-buffer)))
                   (if file-precious-flag
-                      ;; If file is precious, rename it away before
-                      ;; overwriting it.
-                      (let ((rename t)
-                            realname tempname temp)
-                        ;; Chase symlinks; rename the ultimate actual file.
-                        (setq realname buffer-file-name)
-                        (while (setq temp (file-symlink-p realname))
-                          (setq realname temp))
-                        (setq tempname (concat realname "#"))
-                        (condition-case ()
-                            (progn (rename-file realname tempname t)
-                                   (setq setmodes (file-modes tempname)))
-                          (file-error (setq rename nil tempname nil)))
-                        (if (file-directory-p realname)
-                            (error "%s is a directory" realname))
+                      ;; If file is precious, write temp name, then rename it.
+                      (let ((dir (file-name-directory buffer-file-name))
+                            (realname buffer-file-name)
+                            tempname temp nogood i succeed)
+                        (setq i 0)
+                        (setq nogood t)
+                        ;; Find the temporary name to write under.
+                        (while nogood
+                          (setq tempname (format "%s#tmp#%d" dir i))
+                          (setq nogood (file-exists-p tempname))
+                          (setq i (1+ i)))
                         (unwind-protect
                             (progn (clear-visited-file-modtime)
                                    (write-region (point-min) (point-max)
-                                                 realname nil t)
-                                   (setq rename nil))
-                          ;; If rename is still t, writing failed.
-                          ;; So rename the old file back to original name,
-                          (if rename
-                              (progn
-                                (rename-file tempname realname t)
-                                (clear-visited-file-modtime))
-                            ;; Otherwise we don't need the original file,
-                            ;; so flush it, if we still have it.
-                            ;; If rename failed due to name length restriction
-                            ;; then TEMPNAME is now nil.
-                            (if tempname
-                                (condition-case ()
-                                    (delete-file tempname)
-                                  (error nil))))))
+                                                 tempname nil realname)
+                                   (setq succeed t))
+                          ;; If writing the temp file fails,
+                          ;; delete the temp file.
+                          (or succeed (delete-file tempname)))
+                        ;; We succeeded in writing the temp file,
+                        ;; so rename it.
+                        (rename-file tempname buffer-file-name t))
                     ;; If file not writable, see if we can make it writable
                     ;; temporarily while we write it.
                     ;; But no need to do so if we have just backed it up
@@ -897,9 +1281,10 @@ the last real save, but optional arg FORCE non-nil means delete anyway."
                            (set-file-modes buffer-file-name 511)))
                     (write-region (point-min) (point-max)
                                   buffer-file-name nil t)))))
+         (setq buffer-file-number (nth 10 (file-attributes buffer-file-name)))
          (if setmodes
              (condition-case ()
-                  (set-file-modes buffer-file-name setmodes)
+                 (set-file-modes buffer-file-name setmodes)
                (error nil))))
        ;; If the auto-save file was recent before this command,
        ;; delete it now.
@@ -907,38 +1292,47 @@ the last real save, but optional arg FORCE non-nil means delete anyway."
        (run-hooks 'after-save-hooks))
     (message "(No changes need to be saved)")))
 
-
-(require 'map-ynp)
-
 (defun save-some-buffers (&optional arg exiting)
   "Save some modified file-visiting buffers.  Asks user about each one.
-With argument, saves all with no questions."
+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."
   (interactive "P")
-  (if (zerop (map-y-or-n-p
-             (function
-              (lambda (buffer)
-                (and (buffer-modified-p buffer)
-                     (or
-                      (buffer-file-name buffer)
-                      (and exiting
-                           (save-excursion
-                             (set-buffer buffer)
-                             buffer-offer-save (> (buffer-size) 0))))
-                     (if arg
-                         t
-                       (if (buffer-file-name buffer)
-                           (format "Save file %s? "
-                                   (buffer-file-name buffer))
-                         (format "Save buffer %s? "
-                                 (buffer-name buffer)))))))
-             (function
-              (lambda (buffer)
-                (save-excursion
+  (save-window-excursion
+    (if (zerop (map-y-or-n-p
+               (function
+                (lambda (buffer)
+                  (and (buffer-modified-p buffer)
+                       (or
+                        (buffer-file-name buffer)
+                        (and exiting
+                             (progn
+                               (set-buffer buffer)
+                               (and buffer-offer-save (> (buffer-size) 0)))))
+                       (if arg
+                           t
+                         (if (buffer-file-name buffer)
+                             (format "Save file %s? "
+                                     (buffer-file-name buffer))
+                           (format "Save buffer %s? "
+                                   (buffer-name buffer)))))))
+               (function
+                (lambda (buffer)
                   (set-buffer buffer)
-                  (save-buffer))))
-             (buffer-list)
-             '("buffer" "buffers" "save")))
-      (message "(No files need saving)")))
+                  (save-buffer)))
+               (buffer-list)
+               '("buffer" "buffers" "save")
+               (list (list ?\C-r (lambda (buf)
+                                   (view-buffer buf)
+                                   (setq view-exit-action
+                                         '(lambda (ignore)
+                                            (exit-recursive-edit)))
+                                   (recursive-edit)
+                                   ;; Return nil to ask about BUF again.
+                                   nil)
+                           "display the current buffer"))
+               ))
+       (message "(No files need saving)"))))
 \f
 (defun not-modified (&optional arg)
   "Mark current buffer as unmodified, not needing to be saved.
@@ -1003,6 +1397,23 @@ or multiple mail buffers, etc."
     (kill-buffer new-buf)
     (rename-buffer name)
     (set-buffer-modified-p (buffer-modified-p)))) ; force mode line update
+
+(defun make-directory (dir &optional parents)
+  "Create the directory DIR and any nonexistent parent dirs."
+  (interactive "FMake directory: \nP")
+  (let ((handler (find-file-name-handler dir)))
+    (if handler
+       (funcall handler 'make-directory dir parents)
+      (if (not parents)
+         (make-directory-internal dir)
+       (let ((dir (directory-file-name (expand-file-name dir)))
+             create-list)
+         (while (not (file-exists-p dir))
+           (setq create-list (cons dir create-list)        
+                 dir (directory-file-name (file-name-directory dir))))
+         (while create-list
+           (make-directory-internal (car create-list))
+           (setq create-list (cdr create-list))))))))
 \f
 (put 'revert-buffer-function 'permanent-local t)
 (defvar revert-buffer-function nil
@@ -1014,22 +1425,21 @@ or multiple mail buffers, etc."
 Gets two args, first the nominal file name to use,
 and second, t if reading the auto-save file.")
 
-(defun revert-buffer (&optional arg noconfirm)
+(defun revert-buffer (&optional check-auto noconfirm)
   "Replace the buffer text with the text of the visited file on disk.
 This undoes all changes since the file was visited or saved.
-If latest auto-save file is more recent than the visited file,
-asks user whether to use that instead.
-
-Optional first argument ARG means don't offer to use auto-save file.
-This is the prefix arg when called interactively.
+With a prefix argument, offer to revert from latest auto-save file, if
+that is more recent than the visited file.
+When called from lisp, this is the first argument, CHECK-AUTO; it is optional.
 Optional second argument NOCONFIRM means don't ask for confirmation at all.
 
-If `revert-buffer-function' value is non-nil, it is called to do the work."
+If the value of `revert-buffer-function' is non-nil, it is called to
+do the work."
   (interactive "P")
   (if revert-buffer-function
-      (funcall revert-buffer-function arg noconfirm)
+      (funcall revert-buffer-function (not check-auto) noconfirm)
     (let* ((opoint (point))
-          (auto-save-p (and (null arg) (recent-auto-save-p)
+          (auto-save-p (and check-auto (recent-auto-save-p)
                             buffer-auto-save-file-name
                             (file-readable-p buffer-auto-save-file-name)
                             (y-or-n-p
@@ -1045,7 +1455,7 @@ If `revert-buffer-function' value is non-nil, it is called to do the work."
             ;; If file was backed up but has changed since,
             ;; we shd make another backup.
             (and (not auto-save-p)
-                 (not (verify-visited-file-modtime))
+                 (not (verify-visited-file-modtime (current-buffer)))
                  (setq buffer-backed-up nil))
             ;; Get rid of all undo records for this buffer.
             (or (eq buffer-undo-list t)
@@ -1066,7 +1476,7 @@ If `revert-buffer-function' value is non-nil, it is called to do the work."
                   (erase-buffer))
                 (insert-file-contents file-name (not auto-save-p))))
             (goto-char (min opoint (point-max)))
-            (after-find-file nil)
+            (after-find-file nil nil t)
             t)))))
 
 (defun recover-file (file)
@@ -1091,13 +1501,14 @@ If `revert-buffer-function' value is non-nil, it is called to do the work."
                 (with-output-to-temp-buffer "*Directory*"
                   (buffer-disable-undo standard-output)
                   (call-process "ls" nil standard-output nil
-                                "-l" file file-name)))
+                                (if (file-symlink-p file) "-lL" "-l")
+                                file file-name)))
             (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))
             (erase-buffer)
             (insert-file-contents file-name nil))
-          (after-find-file nil))
+          (after-find-file nil nil t))
          (t (error "Recover-file cancelled.")))))
 
 (defun kill-some-buffers ()
@@ -1119,7 +1530,7 @@ If `revert-buffer-function' value is non-nil, it is called to do the work."
 \f
 (defun auto-save-mode (arg)
   "Toggle auto-saving of contents of current buffer.
-With ARG, turn auto-saving on if positive, else off."
+With prefix argument ARG, turn auto-saving on if positive, else off."
   (interactive "P")
   (setq buffer-auto-save-file-name
         (and (if (null arg)
@@ -1195,23 +1606,59 @@ and `list-directory-verbose-switches'."
       (princ "Directory ")
       (princ dirname)
       (terpri)
+      (save-excursion
+       (set-buffer "*Directory*")
+       (let ((wildcard (not (file-directory-p dirname))))
+         (insert-directory dirname switches wildcard (not wildcard)))))))
+
+(defvar insert-directory-program "ls"
+  "Absolute or relative name of the `ls' program used by `insert-directory'.")
+
+;; insert-directory
+;; - must insert _exactly_one_line_ describing FILE if WILDCARD and
+;;   FULL-DIRECTORY-P is nil.
+;;   The single line of output must display FILE's name as it was
+;;   given, namely, an absolute path name.
+;; - must insert exactly one line for each file if WILDCARD or
+;;   FULL-DIRECTORY-P is t, plus one optional "total" line
+;;   before the file lines, plus optional text after the file lines.
+;;   Lines are delimited by "\n", so filenames containing "\n" are not
+;;   allowed.
+;;   File lines should display the basename.
+;; - must be consistent with
+;;   - functions dired-move-to-filename, (these two define what a file line is)
+;;              dired-move-to-end-of-filename,
+;;              dired-between-files, (shortcut for (not (dired-move-to-filename)))
+;;              dired-insert-headerline
+;;              dired-after-subdir-garbage (defines what a "total" line is)
+;;   - variable dired-subdir-regexp
+(defun insert-directory (file switches &optional wildcard full-directory-p)
+  "Insert directory listing for of FILE, formatted according to SWITCHES.
+Leaves point after the inserted text.
+Optional third arg WILDCARD means treat FILE as shell wildcard.
+Optional fourth arg FULL-DIRECTORY-P means file is a directory and
+switches do not contain `d', so that a full listing is expected.
+
+This works by running a directory listing program
+whose name is in the variable `ls-program'.
+If WILDCARD, it also runs the shell specified by `shell-file-name'."
+  (let ((handler (find-file-name-handler file)))
+    (if handler
+       (funcall handler 'insert-directory file switches
+                wildcard full-directory-p)
       (if (eq system-type 'vax-vms)
-         (vms-read-directory dirname switches standard-output)
-       (if (file-directory-p dirname)
-           (save-excursion
-             (set-buffer "*Directory*")
-             (call-process "ls" nil standard-output nil switches
-                           (setq default-directory
-                                 (file-name-as-directory dirname))))
-         (let ((default-directory (file-name-directory dirname)))
-           (if (file-exists-p default-directory)
-               (call-process shell-file-name nil standard-output nil
-                             "-c" (concat "exec ls "
-                                          switches " "
-                                          (file-name-nondirectory dirname)))
-             (princ "No such directory: ")
-             (princ dirname)
-             (terpri))))))))
+         (vms-read-directory file switches (current-buffer))
+       (if wildcard
+           (let ((default-directory (file-name-directory file)))
+             (call-process shell-file-name nil t nil
+                           "-c" (concat insert-directory-program
+                                        " -d " switches " "
+                                        (file-name-nondirectory file))))
+;;;      ;; Chase links till we reach a non-link.
+;;;      (let (symlink)
+;;;        (while (setq symlink (file-symlink-p file))
+;;;          (setq file symlink)))
+         (call-process insert-directory-program nil t nil switches file))))))
 
 (defun save-buffers-kill-emacs (&optional arg)
   "Offer to save each buffer, then kill this Emacs process.
@@ -1228,7 +1675,7 @@ With prefix arg, silently save all file-visiting buffers, then kill."
           (let ((processes (process-list))
                 active)
             (while processes
-              (and (memq (process-status (car processes)) '(run stop))
+              (and (memq (process-status (car processes)) '(run stop open))
                    (let ((val (process-kill-without-query (car processes))))
                      (process-kill-without-query (car processes) val)
                      val)
@@ -1254,3 +1701,11 @@ With prefix arg, silently save all file-visiting buffers, then kill."
 (define-key ctl-x-4-map "r" 'find-file-read-only-other-window)
 (define-key ctl-x-4-map "\C-f" 'find-file-other-window)
 (define-key ctl-x-4-map "b" 'switch-to-buffer-other-window)
+(define-key ctl-x-4-map "\C-o" 'display-buffer)
+
+(define-key ctl-x-5-map "b" 'switch-to-buffer-other-frame)
+(define-key ctl-x-5-map "f" 'find-file-other-frame)
+(define-key ctl-x-5-map "\C-f" 'find-file-other-frame)
+(define-key ctl-x-5-map "r" 'find-file-read-only-other-frame)
+
+;;; files.el ends here