]> code.delx.au - gnu-emacs/blobdiff - lisp/dired-aux.el
(ibuffer-forward-line): Just skip header if we're
[gnu-emacs] / lisp / dired-aux.el
index ebab6fee43882def7e823b82969c77e3b978051a..855deb2702cf5b1e46547b45f2efbf5dcde0a6cf 100644 (file)
@@ -1,8 +1,11 @@
 ;;; dired-aux.el --- less commonly used parts of dired  -*-byte-compile-dynamic: t;-*-
 
 ;;; dired-aux.el --- less commonly used parts of dired  -*-byte-compile-dynamic: t;-*-
 
-;; Copyright (C) 1985, 1986, 1992, 1994 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001
+;;   Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
+;; Maintainer: FSF
+;; Keywords: files
 
 ;; This file is part of GNU Emacs.
 
 
 ;; This file is part of GNU Emacs.
 
@@ -43,7 +46,8 @@
 ;;;###autoload
 (defun dired-diff (file &optional switches)
   "Compare file at point with file FILE using `diff'.
 ;;;###autoload
 (defun dired-diff (file &optional switches)
   "Compare file at point with file FILE using `diff'.
-FILE defaults to the file at the mark.
+FILE defaults to the file at the mark.  (That's the mark set by
+\\[set-mark-command], not by Dired's \\[dired-mark] command.)
 The prompted-for file is the first file given to `diff'.
 With prefix arg, prompt for second argument SWITCHES,
  which is options for `diff'."
 The prompted-for file is the first file given to `diff'.
 With prefix arg, prompt for second argument SWITCHES,
  which is options for `diff'."
@@ -121,7 +125,7 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
   "Change the group of the marked (or next ARG) files."
   (interactive "P")
   (if (memq system-type '(ms-dos windows-nt))
   "Change the group of the marked (or next ARG) files."
   (interactive "P")
   (if (memq system-type '(ms-dos windows-nt))
-      (error "chgrp not supported on this system."))
+      (error "chgrp not supported on this system"))
   (dired-do-chxxx "Group" "chgrp" 'chgrp arg))
 
 ;;;###autoload
   (dired-do-chxxx "Group" "chgrp" 'chgrp arg))
 
 ;;;###autoload
@@ -129,7 +133,7 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
   "Change the owner of the marked (or next ARG) files."
   (interactive "P")
   (if (memq system-type '(ms-dos windows-nt))
   "Change the owner of the marked (or next ARG) files."
   (interactive "P")
   (if (memq system-type '(ms-dos windows-nt))
-      (error "chown not supported on this system."))
+      (error "chown not supported on this system"))
   (dired-do-chxxx "Owner" dired-chown-program 'chown arg))
 
 ;; Process all the files in FILES in batches of a convenient size,
   (dired-do-chxxx "Owner" dired-chown-program 'chown arg))
 
 ;; Process all the files in FILES in batches of a convenient size,
@@ -150,7 +154,7 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
        ;; and this file won't fit in the length limit, process now.
        (if (and pending (> (+ thislength pending-length) max))
            (setq failures
        ;; and this file won't fit in the length limit, process now.
        (if (and pending (> (+ thislength pending-length) max))
            (setq failures
-                 (nconc (apply function (append args pending))
+                 (nconc (apply function (append args (nreverse pending)))
                         failures)
                  pending nil
                  pending-length 0))
                         failures)
                  pending nil
                  pending-length 0))
@@ -160,7 +164,7 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
        (setq pending files)
        (setq pending-length (+ thislength pending-length))
        (setq files rest)))
        (setq pending files)
        (setq pending-length (+ thislength pending-length))
        (setq files rest)))
-    (nconc (apply function (append args pending))
+    (nconc (apply function (append args (nreverse pending)))
           failures)))
 
 ;;;###autoload
           failures)))
 
 ;;;###autoload
@@ -244,7 +248,7 @@ with a prefix argument."
 
 (defun dired-map-dired-file-lines (fun)
   ;; Perform FUN with point at the end of each non-directory line.
 
 (defun dired-map-dired-file-lines (fun)
   ;; Perform FUN with point at the end of each non-directory line.
-  ;; FUN takes one argument, the filename (complete pathname).
+  ;; FUN takes one argument, the absolute filename.
   (save-excursion
     (let (file buffer-read-only)
       (goto-char (point-min))
   (save-excursion
     (let (file buffer-read-only)
       (goto-char (point-min))
@@ -267,7 +271,7 @@ with a prefix argument."
       ;;The caller may want to flag some of these files for deletion.
       (let* ((base-versions
              (concat (file-name-nondirectory fn) ".~"))
       ;;The caller may want to flag some of these files for deletion.
       (let* ((base-versions
              (concat (file-name-nondirectory fn) ".~"))
-            (bv-length (length base-versions))
+            (backup-extract-version-start (length base-versions))
             (possibilities (file-name-all-completions
                             base-versions
                             (file-name-directory fn)))
             (possibilities (file-name-all-completions
                             base-versions
                             (file-name-directory fn)))
@@ -291,18 +295,6 @@ with a prefix argument."
                (insert dired-del-marker)))))
 \f
 ;;; Shell commands
                (insert dired-del-marker)))))
 \f
 ;;; Shell commands
-;;>>> install (move this function into simple.el)
-(defun dired-shell-quote (filename)
-  "Quote a file name for inferior shell (see variable `shell-file-name')."
-  ;; Quote everything except POSIX filename characters.
-  ;; This should be safe enough even for really weird shells.
-  (let ((result "") (start 0) end)
-    (while (string-match "[^-0-9a-zA-Z_./]" filename start)
-      (setq end (match-beginning 0)
-           result (concat result (substring filename start end)
-                          "\\" (substring filename end (1+ end)))
-           start (1+ end)))
-    (concat result (substring filename start))))
 
 (defun dired-read-shell-command (prompt arg files)
 ;;  "Read a dired shell command prompting with PROMPT (using read-string).
 
 (defun dired-read-shell-command (prompt arg files)
 ;;  "Read a dired shell command prompting with PROMPT (using read-string).
@@ -318,47 +310,73 @@ with a prefix argument."
 ;; The in-background argument is only needed in Emacs 18 where
 ;; shell-command doesn't understand an appended ampersand `&'.
 ;;;###autoload
 ;; The in-background argument is only needed in Emacs 18 where
 ;; shell-command doesn't understand an appended ampersand `&'.
 ;;;###autoload
-(defun dired-do-shell-command (command &optional arg)
+(defun dired-do-shell-command (command &optional arg file-list)
   "Run a shell command COMMAND on the marked files.
 If no files are marked or a specific numeric prefix arg is given,
 the next ARG files are used.  Just \\[universal-argument] means the current file.
 The prompt mentions the file(s) or the marker, as appropriate.
 
   "Run a shell command COMMAND on the marked files.
 If no files are marked or a specific numeric prefix arg is given,
 the next ARG files are used.  Just \\[universal-argument] means the current file.
 The prompt mentions the file(s) or the marker, as appropriate.
 
-If there is output, it goes to a separate buffer.
+If there is a `*' in COMMAND, surrounded by whitespace, this runs
+COMMAND just once with the entire file list substituted there.
 
 
-Normally the command is run on each file individually.
-However, if there is a `*' in the command then it is run
-just once with the entire file list substituted there.
+If there is no `*', but there is a `?' in COMMAND, surrounded by
+whitespace, this runs COMMAND on each file individually with the
+file name substituted for `?'.
 
 
-No automatic redisplay of dired buffers is attempted, as there's no
-telling what files the command may have changed.  Type
-\\[dired-do-redisplay] to redisplay the marked files.
+Otherwise, this runs COMMAND on each file individually with the
+file name added at the end of COMMAND (separated by a space).
 
 
-The shell command has the top level directory as working directory, so
-output files usually are created there instead of in a subdir."
+`*' and `?' when not surrounded by whitespace have no special
+significance for `dired-do-shell-command', and are passed through
+normally to the shell, but you must confirm first.  To pass `*' by
+itself to the shell as a wildcard, type `*\"\"'.
+
+If COMMAND produces output, it goes to a separate buffer.
+
+This feature does not try to redisplay Dired buffers afterward, as
+there's no telling what files COMMAND may have changed.
+Type \\[dired-do-redisplay] to redisplay the marked files.
+
+When COMMAND runs, its working directory is the top-level directory of
+the Dired buffer, so output files usually are created there instead of
+in a subdir.
+
+In a noninteractive call (from Lisp code), you must specify
+the list of file names explicitly with the FILE-LIST argument."
 ;;Functions dired-run-shell-command and dired-shell-stuff-it do the
 ;;actual work and can be redefined for customization.
 ;;Functions dired-run-shell-command and dired-shell-stuff-it do the
 ;;actual work and can be redefined for customization.
-  (interactive (list
-               ;; Want to give feedback whether this file or marked files are used:
-               (dired-read-shell-command (concat "! on "
-                                                 "%s: ")
-                                         current-prefix-arg
-                                         (dired-get-marked-files
-                                          t current-prefix-arg))
-               current-prefix-arg))
-  (let* ((on-each (not (string-match "\\*" command)))
-        (file-list (dired-get-marked-files t arg)))
-    (if on-each
-       (dired-bunch-files
-        (- 10000 (length command))
-        (function (lambda (&rest files)
-                    (dired-run-shell-command
-                     (dired-shell-stuff-it command files t arg))))
-        nil
-        file-list)
-      ;; execute the shell command
-      (dired-run-shell-command
-       (dired-shell-stuff-it command file-list nil arg)))))
+  (interactive
+   (let ((files (dired-get-marked-files t current-prefix-arg)))
+     (list
+      ;; Want to give feedback whether this file or marked files are used:
+      (dired-read-shell-command (concat "! on "
+                                       "%s: ")
+                               current-prefix-arg
+                               files)
+      current-prefix-arg
+      files)))
+  (let* ((on-each (not (string-match "\\(^\\|[ \t]\\)\\*\\([ \t]\\|$\\)" command)))
+        (subst (not (string-match "\\(^\\|[ \t]\\)\\?\\([ \t]\\|$\\)" command)))
+        (star (not (string-match "\\*" command)))
+        (qmark (not (string-match "\\?" command))))
+    ;; Get confirmation for wildcards that may have been meant
+    ;; to control substitution of a file name or the file name list.
+    (if (cond ((and star (not on-each))
+              (y-or-n-p "Confirm--do you mean to use `*' as a wildcard? "))
+             ((and qmark (not subst))
+              (y-or-n-p "Confirm--do you mean to use `?' as a wildcard? "))
+             (t))
+       (if on-each
+           (dired-bunch-files
+            (- 10000 (length command))
+            (function (lambda (&rest files)
+                        (dired-run-shell-command
+                         (dired-shell-stuff-it command files t arg))))
+            nil
+            file-list)
+         ;; execute the shell command
+         (dired-run-shell-command
+          (dired-shell-stuff-it command file-list nil arg))))))
 
 ;; Might use {,} for bash or csh:
 (defvar dired-mark-prefix ""
 
 ;; Might use {,} for bash or csh:
 (defvar dired-mark-prefix ""
@@ -376,25 +394,31 @@ output files usually are created there instead of in a subdir."
 ;; Might be redefined for smarter things and could then use RAW-ARG
 ;; (coming from interactive P and currently ignored) to decide what to do.
 ;; Smart would be a way to access basename or extension of file names.
 ;; Might be redefined for smarter things and could then use RAW-ARG
 ;; (coming from interactive P and currently ignored) to decide what to do.
 ;; Smart would be a way to access basename or extension of file names.
-;; See dired-trns.el for an approach to this.
-  ;; Bug: There is no way to quote a *
-  ;; On the other hand, you can never accidentally get a * into your cmd.
   (let ((stuff-it
   (let ((stuff-it
-        (if (string-match "\\*" command)
-            (function (lambda (x)
-                        (dired-replace-in-string "\\*" x command)))
-          (function (lambda (x) (concat command " " x))))))
+        (cond ((string-match "\\(^\\|[ \t]\\)\\*\\([ \t]\\|$\\)" command)
+               (lambda (x)
+                 (string-match "\\(^\\|[ \t]\\)\\(\\*\\)\\([ \t]\\|$\\)" command)
+                 (replace-match x t t command 2)))
+              ((string-match "\\(^\\|[ \t]\\)\\?\\([ \t]\\|$\\)" command)
+               (lambda (x)
+                 (string-match "\\(^\\|[ \t]\\)\\(\\?\\)\\([ \t]\\|$\\)" command)
+                 (replace-match x t t command 2)))
+              (t (lambda (x) (concat command dired-mark-separator x))))))
     (if on-each
     (if on-each
-       (mapconcat stuff-it (mapcar 'dired-shell-quote file-list) ";")
-      (let ((fns (mapconcat 'dired-shell-quote
-                           file-list dired-mark-separator)))
+       (mapconcat stuff-it (mapcar 'shell-quote-argument file-list) ";")
+      (let ((files (mapconcat 'shell-quote-argument
+                             file-list dired-mark-separator)))
        (if (> (length file-list) 1)
        (if (> (length file-list) 1)
-           (setq fns (concat dired-mark-prefix fns dired-mark-postfix)))
-       (funcall stuff-it fns)))))
+           (setq files (concat dired-mark-prefix files dired-mark-postfix)))
+       (funcall stuff-it files)))))
 
 ;; This is an extra function so that it can be redefined by ange-ftp.
 (defun dired-run-shell-command (command)
 
 ;; This is an extra function so that it can be redefined by ange-ftp.
 (defun dired-run-shell-command (command)
-  (shell-command command)
+  (let ((handler
+        (find-file-name-handler (directory-file-name default-directory)
+                                'shell-command)))
+    (if handler (apply handler 'shell-command (list command))
+      (shell-command command)))
   ;; Return nil for sake of nconc in dired-bunch-files.
   nil)
 \f
   ;; Return nil for sake of nconc in dired-bunch-files.
   nil)
 \f
@@ -446,7 +470,7 @@ output files usually are created there instead of in a subdir."
     (while (/= 0 arg)
       (setq file (dired-get-filename nil t))
       (if (not file)
     (while (/= 0 arg)
       (setq file (dired-get-filename nil t))
       (if (not file)
-         (error "Can only kill file lines.")
+         (error "Can only kill file lines")
        (save-excursion (and file
                             (dired-goto-subdir file)
                             (dired-kill-subdir)))
        (save-excursion (and file
                             (dired-goto-subdir file)
                             (dired-kill-subdir)))
@@ -524,6 +548,7 @@ and use this command with a prefix argument (the value does not matter)."
     ;; For .z, try gunzip.  It might be an old gzip file,
     ;; or it might be from compact? pack? (which?) but gunzip handles both.
     ("\\.z\\'" "" "gunzip")
     ;; For .z, try gunzip.  It might be an old gzip file,
     ;; or it might be from compact? pack? (which?) but gunzip handles both.
     ("\\.z\\'" "" "gunzip")
+    ("\\.bz2\\'" "" "bunzip2")
     ;; This item controls naming for compression.
     ("\\.tar\\'" ".tgz" nil))
   "Control changes in file name suffixes for compression and uncompression.
     ;; This item controls naming for compression.
     ("\\.tar\\'" ".tgz" nil))
   "Control changes in file name suffixes for compression and uncompression.
@@ -756,40 +781,19 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
     (delete-region (point) (progn (forward-line 1) (point)))
     (if file
        (progn
     (delete-region (point) (progn (forward-line 1) (point)))
     (if file
        (progn
-         (dired-add-entry file)
+         (dired-add-entry file nil t)
          ;; Replace space by old marker without moving point.
          ;; Faster than goto+insdel inside a save-excursion?
          (subst-char-in-region opoint (1+ opoint) ?\040 char))))
   (dired-move-to-filename))
 
          ;; Replace space by old marker without moving point.
          ;; Faster than goto+insdel inside a save-excursion?
          (subst-char-in-region opoint (1+ opoint) ?\040 char))))
   (dired-move-to-filename))
 
-(defun dired-fun-in-all-buffers (directory file fun &rest args)
-  ;; In all buffers dired'ing DIRECTORY, run FUN with ARGS.
-  ;; If the buffer has a wildcard pattern, check that it matches FILE.
-  ;; (FILE does not include a directory component.)
-  ;; FILE may be nil, in which case ignore it.
-  ;; Return list of buffers where FUN succeeded (i.e., returned non-nil).
-  (let ((buf-list (dired-buffers-for-dir (expand-file-name directory)
-                                        file))
-       (obuf (current-buffer))
-       buf success-list)
-    (while buf-list
-      (setq buf (car buf-list)
-           buf-list (cdr buf-list))
-      (unwind-protect
-         (progn
-           (set-buffer buf)
-           (if (apply fun args)
-               (setq success-list (cons (buffer-name buf) success-list))))
-       (set-buffer obuf)))
-    success-list))
-
 ;;;###autoload
 (defun dired-add-file (filename &optional marker-char)
   (dired-fun-in-all-buffers
    (file-name-directory filename) (file-name-nondirectory filename)
    (function dired-add-entry) filename marker-char))
 
 ;;;###autoload
 (defun dired-add-file (filename &optional marker-char)
   (dired-fun-in-all-buffers
    (file-name-directory filename) (file-name-nondirectory filename)
    (function dired-add-entry) filename marker-char))
 
-(defun dired-add-entry (filename &optional marker-char)
+(defun dired-add-entry (filename &optional marker-char relative)
   ;; Add a new entry for FILENAME, optionally marking it
   ;; with MARKER-CHAR (a character, else dired-marker-char is used).
   ;; Note that this adds the entry `out of order' if files sorted by
   ;; Add a new entry for FILENAME, optionally marking it
   ;; with MARKER-CHAR (a character, else dired-marker-char is used).
   ;; Note that this adds the entry `out of order' if files sorted by
@@ -799,12 +803,15 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
   ;; Hidden subdirs are exposed if a file is added there.
   (setq filename (directory-file-name filename))
   ;; Entry is always for files, even if they happen to also be directories
   ;; Hidden subdirs are exposed if a file is added there.
   (setq filename (directory-file-name filename))
   ;; Entry is always for files, even if they happen to also be directories
-  (let ((opoint (point))
-       (cur-dir (dired-current-directory))
-       (orig-file-name filename)
-       (directory (file-name-directory filename))
-       reason)
-    (setq filename (file-name-nondirectory filename)
+  (let* ((opoint (point))
+        (cur-dir (dired-current-directory))
+        (orig-file-name filename)
+        (directory (if relative cur-dir (file-name-directory filename)))
+        reason)
+    (setq filename
+         (if relative
+             (file-relative-name filename directory)
+           (file-name-nondirectory filename))
          reason
          (catch 'not-found
            (if (string= directory cur-dir)
          reason
          (catch 'not-found
            (if (string= directory cur-dir)
@@ -813,14 +820,14 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
                  (if (eq (following-char) ?\r)
                      (dired-unhide-subdir))
                  ;; We are already where we should be, except when
                  (if (eq (following-char) ?\r)
                      (dired-unhide-subdir))
                  ;; We are already where we should be, except when
-                 ;; point is before the subdir line or its total line.
+                ;; point is before the subdir line or its total line.
                  (let ((p (dired-after-subdir-garbage cur-dir)))
                    (if (< (point) p)
                        (goto-char p))))
              ;; else try to find correct place to insert
              (if (dired-goto-subdir directory)
                  (let ((p (dired-after-subdir-garbage cur-dir)))
                    (if (< (point) p)
                        (goto-char p))))
              ;; else try to find correct place to insert
              (if (dired-goto-subdir directory)
-                 (progn;; unhide if necessary
-                   (if (looking-at "\r");; point is at end of subdir line
+                 (progn ;; unhide if necessary
+                   (if (looking-at "\r") ;; point is at end of subdir line
                        (dired-unhide-subdir))
                    ;; found - skip subdir and `total' line
                    ;; and uninteresting files like . and ..
                        (dired-unhide-subdir))
                    ;; found - skip subdir and `total' line
                    ;; and uninteresting files like . and ..
@@ -832,7 +839,7 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
              (beginning-of-line)
              (setq opoint (point))
              (dired-add-entry-do-indentation marker-char)
              (beginning-of-line)
              (setq opoint (point))
              (dired-add-entry-do-indentation marker-char)
-             ;; don't expand `.'.  Show just the file name within directory.
+       ;; don't expand `.'.  Show just the file name within directory.
              (let ((default-directory directory))
                (insert-directory filename
                                  (concat dired-actual-switches "d")))
              (let ((default-directory directory))
                (insert-directory filename
                                  (concat dired-actual-switches "d")))
@@ -841,7 +848,7 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
              ;; the relative one.  That may be hard to fix since it
              ;; is probably controlled by something in ftp.
              (goto-char opoint)        
              ;; the relative one.  That may be hard to fix since it
              ;; is probably controlled by something in ftp.
              (goto-char opoint)        
-             (let ((inserted-name (dired-get-filename 'no-dir)))
+             (let ((inserted-name (dired-get-filename 'verbatim)))
                (if (file-name-directory inserted-name)
                    (progn
                      (end-of-line)
                (if (file-name-directory inserted-name)
                    (progn
                      (end-of-line)
@@ -849,11 +856,11 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
                      (insert filename)
                      (forward-char 1))
                  (forward-line 1)))
                      (insert filename)
                      (forward-char 1))
                  (forward-line 1)))
-             ;; Give each line a text property recording info about it.
+           ;; Give each line a text property recording info about it.
              (dired-insert-set-properties opoint (point))
              (forward-line -1)
              (dired-insert-set-properties opoint (point))
              (forward-line -1)
-             (if dired-after-readin-hook;; the subdir-alist is not affected...
-                 (save-excursion;; ...so we can run it right now:
+             (if dired-after-readin-hook ;; the subdir-alist is not affected...
+                 (save-excursion ;; ...so we can run it right now:
                    (save-restriction
                      (beginning-of-line)
                      (narrow-to-region (point) (save-excursion
                    (save-restriction
                      (beginning-of-line)
                      (narrow-to-region (point) (save-excursion
@@ -862,9 +869,9 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
              (dired-move-to-filename))
            ;; return nil if all went well
            nil))
              (dired-move-to-filename))
            ;; return nil if all went well
            nil))
-    (if reason                         ; don't move away on failure
+    (if reason ; don't move away on failure
        (goto-char opoint))
        (goto-char opoint))
-    (not reason)))                     ; return t on success, nil else
+    (not reason))) ; return t on success, nil else
 
 ;; This is a separate function for the sake of nested dired format.
 (defun dired-add-entry-do-indentation (marker-char)
 
 ;; This is a separate function for the sake of nested dired format.
 (defun dired-add-entry-do-indentation (marker-char)
@@ -909,7 +916,7 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
 
 (defun dired-relist-entry (file)
   ;; Relist the line for FILE, or just add it if it did not exist.
 
 (defun dired-relist-entry (file)
   ;; Relist the line for FILE, or just add it if it did not exist.
-  ;; FILE must be an absolute pathname.
+  ;; FILE must be an absolute file name.
   (let (buffer-read-only marker)
     ;; If cursor is already on FILE's line delete-region will cause
     ;; save-excursion to fail because of floating makers,
   (let (buffer-read-only marker)
     ;; If cursor is already on FILE's line delete-region will cause
     ;; save-excursion to fail because of floating makers,
@@ -925,9 +932,26 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
 \f
 ;;; Copy, move/rename, making hard and symbolic links
 
 \f
 ;;; Copy, move/rename, making hard and symbolic links
 
-(defvar dired-backup-overwrite nil
+(defcustom dired-recursive-copies nil
+  "*Decide whether recursive copies are allowed.
+nil means no recursive copies.
+`always' means copy recursively without asking.
+`top' means ask for each directory at top level.
+Anything else means ask for each directory."
+  :type '(choice :tag "Copy directories"
+                (const :tag "No recursive copies" nil)
+                (const :tag "Ask for each directory" t)
+                (const :tag "Ask for each top directory only" top)
+                (const :tag "Copy directories without asking" always))
+  :group 'dired)
+
+(defcustom dired-backup-overwrite nil
   "*Non-nil if Dired should ask about making backups before overwriting files.
   "*Non-nil if Dired should ask about making backups before overwriting files.
-Special value `always' suppresses confirmation.")
+Special value `always' suppresses confirmation."
+  :type '(choice (const :tag "off" nil)
+                (const :tag "suppress" always)
+                (other :tag "ask" t))
+  :group 'dired)
 
 (defvar dired-overwrite-confirmed)
 
 
 (defvar dired-overwrite-confirmed)
 
@@ -941,7 +965,8 @@ Special value `always' suppresses confirmation.")
             (setq backup (car (find-backup-file-name to)))
             (or (eq 'always dired-backup-overwrite)
                 (dired-query 'overwrite-backup-query
             (setq backup (car (find-backup-file-name to)))
             (or (eq 'always dired-backup-overwrite)
                 (dired-query 'overwrite-backup-query
-                             (format "Make backup for existing file `%s'? " to))))
+                             (format "Make backup for existing file `%s'? "
+                                     to))))
        (progn
          (rename-file to backup 0)     ; confirm overwrite of old backup
          (dired-relist-entry backup)))))
        (progn
          (rename-file to backup 0)     ; confirm overwrite of old backup
          (dired-relist-entry backup)))))
@@ -949,7 +974,31 @@ Special value `always' suppresses confirmation.")
 ;;;###autoload
 (defun dired-copy-file (from to ok-flag)
   (dired-handle-overwrite to)
 ;;;###autoload
 (defun dired-copy-file (from to ok-flag)
   (dired-handle-overwrite to)
-  (copy-file from to ok-flag dired-copy-preserve-time))
+  (condition-case ()
+      (dired-copy-file-recursive from to ok-flag dired-copy-preserve-time t
+                                dired-recursive-copies)
+    (file-date-error (message "Can't set date")
+                    (sit-for 1))))
+
+(defun dired-copy-file-recursive (from to ok-flag &optional
+                                      preserve-time top recursive)
+  (if (and recursive
+          (eq t (car (file-attributes from))) ; A directory, no symbolic link.
+          (or (eq recursive 'always)
+              (yes-or-no-p (format "Recursive copies of %s " from))))
+      (let ((files (directory-files from nil dired-re-no-dot)))
+       (if (eq recursive 'top) (setq recursive 'always)) ; Don't ask any more.
+       (if (file-exists-p to)
+           (or top (dired-handle-overwrite to))
+         (make-directory to))
+       (while files
+         (dired-copy-file-recursive
+          (expand-file-name (car files) from)
+          (expand-file-name (car files) to)
+          ok-flag preserve-time nil recursive)
+         (setq files (cdr files))))
+    (or top (dired-handle-overwrite to)) ; Just a file.
+    (copy-file from to ok-flag dired-copy-preserve-time)))
 
 ;;;###autoload
 (defun dired-rename-file (from to ok-flag)
 
 ;;;###autoload
 (defun dired-rename-file (from to ok-flag)
@@ -1058,7 +1107,7 @@ Special value `always' suppresses confirmation.")
 ;; OPERATION (a capitalized string, e.g. `Copy') describes the
 ;; operation performed.  It is used for error logging.
 
 ;; OPERATION (a capitalized string, e.g. `Copy') describes the
 ;; operation performed.  It is used for error logging.
 
-;; FN-LIST is the list of files to copy (full absolute pathnames).
+;; FN-LIST is the list of files to copy (full absolute file names).
 
 ;; NAME-CONSTRUCTOR returns a newfile for every oldfile, or nil to
 ;; skip.  If it skips files for other reasons than a direct user
 
 ;; NAME-CONSTRUCTOR returns a newfile for every oldfile, or nil to
 ;; skip.  If it skips files for other reasons than a direct user
@@ -1134,57 +1183,94 @@ ESC or `q' to not overwrite any of the remaining files,
   (dired-move-to-filename))
 \f
 (defun dired-do-create-files (op-symbol file-creator operation arg
   (dired-move-to-filename))
 \f
 (defun dired-do-create-files (op-symbol file-creator operation arg
-                                            &optional marker-char op1
-                                            how-to)
-  ;; Create a new file for each marked file.
-  ;; Prompts user for target, which is a directory in which to create
-  ;;   the new files.  Target may be a plain file if only one marked
-  ;;   file exists.
-  ;; OP-SYMBOL is the symbol for the operation.  Function `dired-mark-pop-up'
-  ;;   will determine whether pop-ups are appropriate for this OP-SYMBOL.
-  ;; FILE-CREATOR and OPERATION as in dired-create-files.
-  ;; ARG as in dired-get-marked-files.
-  ;; Optional arg OP1 is an alternate form for OPERATION if there is
-  ;;   only one file.
-  ;; Optional arg MARKER-CHAR as in dired-create-files.
-  ;; Optional arg HOW-TO determines how to treat target:
-  ;;   If HOW-TO is not given (or nil), and target is a directory, the
-  ;;     file(s) are created inside the target directory.  If target
-  ;;     is not a directory, there must be exactly one marked file,
-  ;;     else error.
-  ;;   If HOW-TO is t, then target is not modified.  There must be
-  ;;     exactly one marked file, else error.
-  ;; Else HOW-TO is assumed to be a function of one argument, target,
-  ;;     that looks at target and returns a value for the into-dir
-  ;;     variable.  The function dired-into-dir-with-symlinks is provided
-  ;;     for the case (common when creating symlinks) that symbolic
-  ;;     links to directories are not to be considered as directories
-  ;;     (as file-directory-p would if HOW-TO had been nil).
+                                       &optional marker-char op1
+                                       how-to)
+  "Create a new file for each marked file.
+Prompts user for target, which is a directory in which to create
+  the new files.  Target may be a plain file if only one marked
+  file exists.  The way the default for the target directory is
+  computed depends on the value of `dired-dwim-target-directory'.
+OP-SYMBOL is the symbol for the operation.  Function `dired-mark-pop-up'
+  will determine whether pop-ups are appropriate for this OP-SYMBOL.
+FILE-CREATOR and OPERATION as in `dired-create-files'.
+ARG as in `dired-get-marked-files'.
+Optional arg MARKER-CHAR as in `dired-create-files'.
+Optional arg OP1 is an alternate form for OPERATION if there is
+  only one file.
+Optional arg HOW-TO is used to set the value of the into-dir variable
+  which determines how to treat target.
+  If into-dir is set to nil then target is not regarded as a directory,
+    there must be exactly one marked file, else error.
+  Else if into-dir is set to a list, then target is a generalized
+    directory (e.g. some sort of archive).  The first element of into-dir
+    must be a function with at least four arguments:
+      operation as OPERATION above.
+      rfn-list a list of the relative names for the marked files.
+      fn-list a list of the absolute names for the marked files.
+      target.
+      The rest of into-dir are optional arguments.
+  Else into-dir is not a list.  Target is a directory.
+    The marked file(s) are created inside the target directory.
+
+  If HOW-TO is not given (or nil), then into-dir is set to true if
+    target is a directory and otherwise to nil.
+  Else if HOW-TO is t, then into-dir is set to nil.
+  Else HOW-TO is assumed to be a function of one argument, target,
+    that looks at target and returns a value for the into-dir
+    variable.  The function `dired-into-dir-with-symlinks' is provided
+    for the case (common when creating symlinks) that symbolic
+    links to directories are not to be considered as directories
+    (as `file-directory-p' would if HOW-TO had been nil)."
   (or op1 (setq op1 operation))
   (let* ((fn-list (dired-get-marked-files nil arg))
   (or op1 (setq op1 operation))
   (let* ((fn-list (dired-get-marked-files nil arg))
-        (fn-count (length fn-list))
-        (target (expand-file-name
+        (rfn-list (mapcar (function dired-make-relative) fn-list))
+        (dired-one-file        ; fluid variable inside dired-create-files
+         (and (consp fn-list) (null (cdr fn-list)) (car fn-list)))
+        (target-dir (dired-dwim-target-directory))
+        (default (and dired-one-file
+                      (expand-file-name (file-name-nondirectory (car fn-list))
+                                        target-dir)))
+        (target (expand-file-name ; fluid variable inside dired-create-files
                   (dired-mark-read-file-name
                   (dired-mark-read-file-name
-                   (concat (if (= 1 fn-count) op1 operation) " %s to: ")
-                   (dired-dwim-target-directory)
-                   op-symbol arg (mapcar (function dired-make-relative) fn-list))))
-        (into-dir (cond ((null how-to) (file-directory-p target))
+                   (concat (if dired-one-file op1 operation) " %s to: ")
+                   target-dir op-symbol arg rfn-list default)))
+        (into-dir (cond ((null how-to)
+                         ;; Allow DOS/Windows users to change the letter
+                         ;; case of a directory.  If we don't test these
+                         ;; conditions up front, file-directory-p below
+                         ;; will return t because the filesystem is
+                         ;; case-insensitive, and Emacs will try to move
+                         ;; foo -> foo/foo, which fails.
+                         (if (and (memq system-type '(ms-dos windows-nt))
+                                  (eq op-symbol 'move)
+                                  dired-one-file
+                                  (string= (downcase
+                                            (expand-file-name (car fn-list)))
+                                           (downcase
+                                            (expand-file-name target)))
+                                  (not (string=
+                                        (file-name-nondirectory (car fn-list))
+                                        (file-name-nondirectory target))))
+                             nil
+                           (file-directory-p target)))
                         ((eq how-to t) nil)
                         (t (funcall how-to target)))))
                         ((eq how-to t) nil)
                         (t (funcall how-to target)))))
-    (if (and (> fn-count 1)
-            (not into-dir))
-       (error "Marked %s: target must be a directory: %s" operation target))
-    ;; rename-file bombs when moving directories unless we do this:
-    (or into-dir (setq target (directory-file-name target)))
-    (dired-create-files
-     file-creator operation fn-list
-     (if into-dir                      ; target is a directory
-        ;; This function uses fluid vars into-dir and target when called
-        ;; inside dired-create-files:
-        (function (lambda (from)
-                    (expand-file-name (file-name-nondirectory from) target)))
-       (function (lambda (from) target)))
-     marker-char)))
+    (if (and (consp into-dir) (functionp (car into-dir)))
+       (apply (car into-dir) operation rfn-list fn-list target (cdr into-dir))
+      (if (not (or dired-one-file into-dir))
+         (error "Marked %s: target must be a directory: %s" operation target))
+      ;; rename-file bombs when moving directories unless we do this:
+      (or into-dir (setq target (directory-file-name target)))
+      (dired-create-files
+       file-creator operation fn-list
+       (if into-dir                    ; target is a directory
+          ;; This function uses fluid variable target when called
+          ;; inside dired-create-files:
+          (function
+           (lambda (from)
+             (expand-file-name (file-name-nondirectory from) target)))
+        (function (lambda (from) target)))
+       marker-char))))
 
 ;; Read arguments for a marked-files command that wants a file name,
 ;; perhaps popping up the list of marked files.
 
 ;; Read arguments for a marked-files command that wants a file name,
 ;; perhaps popping up the list of marked files.
@@ -1192,12 +1278,15 @@ ESC or `q' to not overwrite any of the remaining files,
 ;; marks (ARG=nil) or a repeat factor (integerp ARG).
 ;; If the current file was used, the list has but one element and ARG
 ;; does not matter. (It is non-nil, non-integer in that case, namely '(4)).
 ;; marks (ARG=nil) or a repeat factor (integerp ARG).
 ;; If the current file was used, the list has but one element and ARG
 ;; does not matter. (It is non-nil, non-integer in that case, namely '(4)).
+;; DEFAULT is the default value to return if the user just hits RET;
+;; if it is omitted or nil, then the name of the directory is used.
 
 
-(defun dired-mark-read-file-name (prompt dir op-symbol arg files)
+(defun dired-mark-read-file-name (prompt dir op-symbol arg files
+                                        &optional default)
   (dired-mark-pop-up
    nil op-symbol files
    (function read-file-name)
   (dired-mark-pop-up
    nil op-symbol files
    (function read-file-name)
-   (format prompt (dired-mark-prompt arg files)) dir))
+   (format prompt (dired-mark-prompt arg files)) dir default))
 
 (defun dired-dwim-target-directory ()
   ;; Try to guess which target directory the user may want.
 
 (defun dired-dwim-target-directory ()
   ;; Try to guess which target directory the user may want.
@@ -1241,6 +1330,10 @@ ESC or `q' to not overwrite any of the remaining files,
 ;; just have to remove that symlink by hand before making your marked
 ;; symlinks.
 
 ;; just have to remove that symlink by hand before making your marked
 ;; symlinks.
 
+(defvar dired-copy-how-to-fn nil
+  "nil or a function used by `dired-do-copy' to determine target.
+See HOW-TO argument for `dired-do-create-files'.")
+
 ;;;###autoload
 (defun dired-do-copy (&optional arg)
   "Copy all marked (or next ARG) files, or copy the current file.
 ;;;###autoload
 (defun dired-do-copy (&optional arg)
   "Copy all marked (or next ARG) files, or copy the current file.
@@ -1248,11 +1341,15 @@ This normally preserves the last-modified date when copying.
 When operating on just the current file, you specify the new name.
 When operating on multiple or marked files, you specify a directory,
 and new copies of these files are made in that directory
 When operating on just the current file, you specify the new name.
 When operating on multiple or marked files, you specify a directory,
 and new copies of these files are made in that directory
-with the same names that the files currently have."
+with the same names that the files currently have.  The default
+suggested for the target directory depends on the value of
+`dired-dwim-target', which see."
   (interactive "P")
   (interactive "P")
-  (dired-do-create-files 'copy (function dired-copy-file)
+  (let ((dired-recursive-copies dired-recursive-copies))
+    (dired-do-create-files 'copy (function dired-copy-file)
                           (if dired-copy-preserve-time "Copy [-p]" "Copy")
                           (if dired-copy-preserve-time "Copy [-p]" "Copy")
-                          arg dired-keep-marker-copy))
+                          arg dired-keep-marker-copy
+                          nil dired-copy-how-to-fn)))
 
 ;;;###autoload
 (defun dired-do-symlink (&optional arg)
 
 ;;;###autoload
 (defun dired-do-symlink (&optional arg)
@@ -1260,7 +1357,9 @@ with the same names that the files currently have."
 When operating on just the current file, you specify the new name.
 When operating on multiple or marked files, you specify a directory
 and new symbolic links are made in that directory
 When operating on just the current file, you specify the new name.
 When operating on multiple or marked files, you specify a directory
 and new symbolic links are made in that directory
-with the same names that the files currently have."
+with the same names that the files currently have.  The default
+suggested for the target directory depends on the value of
+`dired-dwim-target', which see."
   (interactive "P")
   (dired-do-create-files 'symlink (function make-symbolic-link)
                           "Symlink" arg dired-keep-marker-symlink))
   (interactive "P")
   (dired-do-create-files 'symlink (function make-symbolic-link)
                           "Symlink" arg dired-keep-marker-symlink))
@@ -1271,7 +1370,9 @@ with the same names that the files currently have."
 When operating on just the current file, you specify the new name.
 When operating on multiple or marked files, you specify a directory
 and new hard links are made in that directory
 When operating on just the current file, you specify the new name.
 When operating on multiple or marked files, you specify a directory
 and new hard links are made in that directory
-with the same names that the files currently have."
+with the same names that the files currently have.  The default
+suggested for the target directory depends on the value of
+`dired-dwim-target', which see."
   (interactive "P")
   (dired-do-create-files 'hardlink (function add-name-to-file)
                           "Hardlink" arg dired-keep-marker-hardlink))
   (interactive "P")
   (dired-do-create-files 'hardlink (function add-name-to-file)
                           "Hardlink" arg dired-keep-marker-hardlink))
@@ -1280,7 +1381,9 @@ with the same names that the files currently have."
 (defun dired-do-rename (&optional arg)
   "Rename current file or all marked (or next ARG) files.
 When renaming just the current file, you specify the new name.
 (defun dired-do-rename (&optional arg)
   "Rename current file or all marked (or next ARG) files.
 When renaming just the current file, you specify the new name.
-When renaming multiple or marked files, you specify a directory."
+When renaming multiple or marked files, you specify a directory.
+The default suggested for the target directory depends on the value
+of `dired-dwim-target', which see."
   (interactive "P")
   (dired-do-create-files 'move (function dired-rename-file)
                         "Move" arg dired-keep-marker-rename "Rename"))
   (interactive "P")
   (dired-do-create-files 'move (function dired-rename-file)
                         "Move" arg dired-keep-marker-rename "Rename"))
@@ -1295,7 +1398,7 @@ When renaming multiple or marked files, you specify a directory."
   ;; ARG as in dired-get-marked-files.
   ;; Matches each marked file against REGEXP and constructs the new
   ;;   filename from NEWNAME (like in function replace-match).
   ;; ARG as in dired-get-marked-files.
   ;; Matches each marked file against REGEXP and constructs the new
   ;;   filename from NEWNAME (like in function replace-match).
-  ;; Optional arg WHOLE-PATH means match/replace the whole pathname
+  ;; Optional arg WHOLE-PATH means match/replace the whole file name
   ;;   instead of only the non-directory part of the file.
   ;; Optional arg MARKER-CHAR as in dired-create-files.
   (let* ((fn-list (dired-get-marked-files nil arg))
   ;;   instead of only the non-directory part of the file.
   ;; Optional arg MARKER-CHAR as in dired-create-files.
   (let* ((fn-list (dired-get-marked-files nil arg))
@@ -1361,14 +1464,19 @@ Type SPC or `y' to %s one match, DEL or `n' to skip to next,
 
 ;;;###autoload
 (defun dired-do-rename-regexp (regexp newname &optional arg whole-path)
 
 ;;;###autoload
 (defun dired-do-rename-regexp (regexp newname &optional arg whole-path)
-  "Rename marked files containing REGEXP to NEWNAME.
+  "Rename selected files whose names match REGEXP to NEWNAME.
+
+With non-zero prefix argument ARG, the command operates on the next ARG
+files.  Otherwise, it operates on all the marked files, or the current
+file if none are marked.
+
 As each match is found, the user must type a character saying
   what to do with it.  For directions, type \\[help-command] at that time.
 NEWNAME may contain \\=\\<n> or \\& as in `query-replace-regexp'.
 REGEXP defaults to the last regexp used.
 As each match is found, the user must type a character saying
   what to do with it.  For directions, type \\[help-command] at that time.
 NEWNAME may contain \\=\\<n> or \\& as in `query-replace-regexp'.
 REGEXP defaults to the last regexp used.
-With a zero prefix arg, renaming by regexp affects the complete
-  pathname - usually only the non-directory part of file names is used
-  and changed."
+
+With a zero prefix arg, renaming by regexp affects the absolute file name.
+Normally, only the non-directory part of the file name is used and changed."
   (interactive (dired-mark-read-regexp "Rename"))
   (dired-do-create-files-regexp
    (function dired-rename-file)
   (interactive (dired-mark-read-regexp "Rename"))
   (dired-do-create-files-regexp
    (function dired-rename-file)
@@ -1376,18 +1484,19 @@ With a zero prefix arg, renaming by regexp affects the complete
 
 ;;;###autoload
 (defun dired-do-copy-regexp (regexp newname &optional arg whole-path)
 
 ;;;###autoload
 (defun dired-do-copy-regexp (regexp newname &optional arg whole-path)
-  "Copy all marked files containing REGEXP to NEWNAME.
-See function `dired-rename-regexp' for more info."
+  "Copy selected files whose names match REGEXP to NEWNAME.
+See function `dired-do-rename-regexp' for more info."
   (interactive (dired-mark-read-regexp "Copy"))
   (interactive (dired-mark-read-regexp "Copy"))
-  (dired-do-create-files-regexp
-   (function dired-copy-file)
-   (if dired-copy-preserve-time "Copy [-p]" "Copy")
-   arg regexp newname whole-path dired-keep-marker-copy))
+  (let ((dired-recursive-copies nil))  ; No recursive copies.
+    (dired-do-create-files-regexp
+     (function dired-copy-file)
+     (if dired-copy-preserve-time "Copy [-p]" "Copy")
+     arg regexp newname whole-path dired-keep-marker-copy)))
 
 ;;;###autoload
 (defun dired-do-hardlink-regexp (regexp newname &optional arg whole-path)
 
 ;;;###autoload
 (defun dired-do-hardlink-regexp (regexp newname &optional arg whole-path)
-  "Hardlink all marked files containing REGEXP to NEWNAME.
-See function `dired-rename-regexp' for more info."
+  "Hardlink selected files whose names match REGEXP to NEWNAME.
+See function `dired-do-rename-regexp' for more info."
   (interactive (dired-mark-read-regexp "HardLink"))
   (dired-do-create-files-regexp
    (function add-name-to-file)
   (interactive (dired-mark-read-regexp "HardLink"))
   (dired-do-create-files-regexp
    (function add-name-to-file)
@@ -1395,8 +1504,8 @@ See function `dired-rename-regexp' for more info."
 
 ;;;###autoload
 (defun dired-do-symlink-regexp (regexp newname &optional arg whole-path)
 
 ;;;###autoload
 (defun dired-do-symlink-regexp (regexp newname &optional arg whole-path)
-  "Symlink all marked files containing REGEXP to NEWNAME.
-See function `dired-rename-regexp' for more info."
+  "Symlink selected files whose names match REGEXP to NEWNAME.
+See function `dired-do-rename-regexp' for more info."
   (interactive (dired-mark-read-regexp "SymLink"))
   (dired-do-create-files-regexp
    (function make-symbolic-link)
   (interactive (dired-mark-read-regexp "SymLink"))
   (dired-do-create-files-regexp
    (function make-symbolic-link)
@@ -1476,6 +1585,7 @@ This function takes some pains to conform to `ls -lR' output."
     ;; insert message so that the user sees the `Mark set' message.
     (push-mark opoint)))
 
     ;; insert message so that the user sees the `Mark set' message.
     (push-mark opoint)))
 
+;;;###autoload
 (defun dired-insert-subdir (dirname &optional switches no-error-if-not-dir-p)
   "Insert this subdirectory into the same dired buffer.
 If it is already present, overwrites previous entry,
 (defun dired-insert-subdir (dirname &optional switches no-error-if-not-dir-p)
   "Insert this subdirectory into the same dired buffer.
 If it is already present, overwrites previous entry,
@@ -1508,7 +1618,7 @@ This function takes some pains to conform to `ls -lR' output."
       (dired-insert-subdir-newpos dirname)) ; else compute new position
     (dired-insert-subdir-doupdate
      dirname elt (dired-insert-subdir-doinsert dirname switches))
       (dired-insert-subdir-newpos dirname)) ; else compute new position
     (dired-insert-subdir-doupdate
      dirname elt (dired-insert-subdir-doinsert dirname switches))
-    (if switches-have-R (dired-build-subdir-alist))
+    (if switches-have-R (dired-build-subdir-alist switches))
     (dired-initial-position dirname)
     (save-excursion (dired-mark-remembered mark-alist))))
 
     (dired-initial-position dirname)
     (save-excursion (dired-mark-remembered mark-alist))))
 
@@ -1544,8 +1654,8 @@ This function takes some pains to conform to `ls -lR' output."
                             (dired-get-subdir-min elt2)))))))
 
 (defun dired-kill-tree (dirname &optional remember-marks)
                             (dired-get-subdir-min elt2)))))))
 
 (defun dired-kill-tree (dirname &optional remember-marks)
-  ;;"Kill all proper subdirs of DIRNAME, excluding DIRNAME itself.
-  ;; With optional arg REMEMBER-MARKS, return an alist of marked files."
+  "Kill all proper subdirs of DIRNAME, excluding DIRNAME itself.
+With optional arg REMEMBER-MARKS, return an alist of marked files."
   (interactive "DKill tree below directory: ")
   (setq dirname (expand-file-name dirname))
   (let ((s-alist dired-subdir-alist) dir m-alist)
   (interactive "DKill tree below directory: ")
   (setq dirname (expand-file-name dirname))
   (let ((s-alist dired-subdir-alist) dir m-alist)
@@ -1614,7 +1724,8 @@ This function takes some pains to conform to `ls -lR' output."
     ;;  moves point.
     ;;  Need a marker for END as this inserts text.
     (goto-char begin)
     ;;  moves point.
     ;;  Need a marker for END as this inserts text.
     (goto-char begin)
-    (dired-insert-headerline dirname)
+    (if (not (looking-at "^  /.*:$"))
+       (dired-insert-headerline dirname))
     ;; point is now like in dired-build-subdir-alist
     (prog1
        (list begin (marker-position end))
     ;; point is now like in dired-build-subdir-alist
     (prog1
        (list begin (marker-position end))
@@ -1641,7 +1752,7 @@ This function takes some pains to conform to `ls -lR' output."
            (run-hooks 'dired-after-readin-hook))))))
 
 (defun dired-tree-lessp (dir1 dir2)
            (run-hooks 'dired-after-readin-hook))))))
 
 (defun dired-tree-lessp (dir1 dir2)
-  ;; Lexicographic order on pathname components, like `ls -lR':
+  ;; Lexicographic order on file name components, like `ls -lR':
   ;; DIR1 < DIR2 iff DIR1 comes *before* DIR2 in an `ls -lR' listing,
   ;;   i.e., iff DIR1 is a (grand)parent dir of DIR2,
   ;;   or DIR1 and DIR2 are in the same parentdir and their last
   ;; DIR1 < DIR2 iff DIR1 comes *before* DIR2 in an `ls -lR' listing,
   ;;   i.e., iff DIR1 is a (grand)parent dir of DIR2,
   ;;   or DIR1 and DIR2 are in the same parentdir and their last
@@ -1747,7 +1858,9 @@ The next char is either \\n, or \\r if DIR is hidden."
 \f
 ;;;###autoload
 (defun dired-mark-subdir-files ()
 \f
 ;;;###autoload
 (defun dired-mark-subdir-files ()
-  "Mark all files except `.' and `..'."
+  "Mark all files except `.' and `..' in current subdirectory.
+If the Dired buffer shows multiple directories, this command
+marks the files listed in the subdirectory that point is in."
   (interactive)
   (let ((p-min (dired-subdir-min)))
     (dired-mark-files-in-region p-min (dired-subdir-max))))
   (interactive)
   (let ((p-min (dired-subdir-min)))
     (dired-mark-files-in-region p-min (dired-subdir-max))))
@@ -1786,7 +1899,7 @@ Lower levels are unaffected."
            dir (file-name-directory (directory-file-name dir))))
     ;;(setq dir (expand-file-name dir))
     (or (dired-goto-subdir dir)
            dir (file-name-directory (directory-file-name dir))))
     ;;(setq dir (expand-file-name dir))
     (or (dired-goto-subdir dir)
-       (error "Cannot go up to %s - not in this tree." dir))))
+       (error "Cannot go up to %s - not in this tree" dir))))
 
 ;;;###autoload
 (defun dired-tree-down ()
 
 ;;;###autoload
 (defun dired-tree-down ()
@@ -1880,18 +1993,35 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
 Stops when a match is found.
 To continue searching for next match, use command \\[tags-loop-continue]."
   (interactive "sSearch marked files (regexp): ")
 Stops when a match is found.
 To continue searching for next match, use command \\[tags-loop-continue]."
   (interactive "sSearch marked files (regexp): ")
-  (tags-search regexp '(dired-get-marked-files)))
+  (tags-search regexp '(dired-get-marked-files nil nil 'dired-nondirectory-p)))
 
 ;;;###autoload
 
 ;;;###autoload
-(defun dired-do-query-replace (from to &optional delimited)
+(defun dired-do-query-replace-regexp (from to &optional delimited)
   "Do `query-replace-regexp' of FROM with TO, on all marked files.
 Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
   "Do `query-replace-regexp' of FROM with TO, on all marked files.
 Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
-If you exit (\\[keyboard-quit] or ESC), you can resume the query replace
+If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
 with the command \\[tags-loop-continue]."
   (interactive
    "sQuery replace in marked files (regexp): \nsQuery replace %s by: \nP")
 with the command \\[tags-loop-continue]."
   (interactive
    "sQuery replace in marked files (regexp): \nsQuery replace %s by: \nP")
-  (tags-query-replace from to delimited '(dired-get-marked-files)))
+  (tags-query-replace from to delimited
+                     '(dired-get-marked-files nil nil 'dired-nondirectory-p)))
+
+(defun dired-nondirectory-p (file)
+  (not (file-directory-p file)))
 \f
 \f
+;;;###autoload
+(defun dired-show-file-type (file &optional deref-symlinks)
+  "Print the type of FILE, according to the `file' command.
+If FILE is a symbolic link and the optional argument DEREF-SYMLINKS is
+true then the type of the file linked to by FILE is printed instead." 
+  (interactive (list (dired-get-filename t) current-prefix-arg))
+  (with-temp-buffer 
+    (if deref-symlinks
+       (call-process "file" nil t t "-L" file)
+      (call-process "file" nil t t file))
+    (when (bolp)
+      (backward-delete-char 1))
+    (message (buffer-string))))
 
 (provide 'dired-aux)
 
 
 (provide 'dired-aux)