]> 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 175e48cd1fc01519956c40b75b2b2326462d6adf..855deb2702cf5b1e46547b45f2efbf5dcde0a6cf 100644 (file)
@@ -1,9 +1,11 @@
 ;;; dired-aux.el --- less commonly used parts of dired  -*-byte-compile-dynamic: t;-*-
 
-;; Copyright (C) 1985, 1986, 1992, 1994, 1998 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>.
 ;; Maintainer: FSF
+;; Keywords: files
 
 ;; This file is part of GNU Emacs.
 
@@ -44,7 +46,8 @@
 ;;;###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'."
@@ -122,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))
-      (error "chgrp not supported on this system."))
+      (error "chgrp not supported on this system"))
   (dired-do-chxxx "Group" "chgrp" 'chgrp arg))
 
 ;;;###autoload
@@ -130,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))
-      (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,
@@ -151,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
-                 (nconc (apply function (append args pending))
+                 (nconc (apply function (append args (nreverse pending)))
                         failures)
                  pending nil
                  pending-length 0))
@@ -161,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)))
-    (nconc (apply function (append args pending))
+    (nconc (apply function (append args (nreverse pending)))
           failures)))
 
 ;;;###autoload
@@ -245,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.
-  ;; 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))
@@ -313,18 +316,33 @@ 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.
   (interactive
@@ -337,18 +355,28 @@ output files usually are created there instead of in a subdir."
                                files)
       current-prefix-arg
       files)))
-  (let* ((on-each (not (string-match "\\*" command))))
-    (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)))))
+  (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 ""
@@ -366,21 +394,23 @@ 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.
-;; 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
-        (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
        (mapconcat stuff-it (mapcar 'shell-quote-argument file-list) ";")
-      (let ((fns (mapconcat 'shell-quote-argument
-                           file-list dired-mark-separator)))
+      (let ((files (mapconcat 'shell-quote-argument
+                             file-list dired-mark-separator)))
        (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)
@@ -440,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)
-         (error "Can only kill file lines.")
+         (error "Can only kill file lines")
        (save-excursion (and file
                             (dired-goto-subdir file)
                             (dired-kill-subdir)))
@@ -518,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")
+    ("\\.bz2\\'" "" "bunzip2")
     ;; This item controls naming for compression.
     ("\\.tar\\'" ".tgz" nil))
   "Control changes in file name suffixes for compression and uncompression.
@@ -756,27 +787,6 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
          (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
@@ -794,10 +804,10 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
   (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 (if relative cur-dir (file-name-directory filename)))
-       reason)
+        (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)
@@ -810,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
-                 ;; 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)
-                 (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 ..
@@ -829,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)
-             ;; 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")))
@@ -838,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)        
-             (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)
@@ -846,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)))
-             ;; 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)
-             (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
@@ -859,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))
-    (if reason                         ; don't move away on failure
+    (if reason ; don't move away on failure
        (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)
@@ -906,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.
-  ;; 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,
@@ -922,6 +932,19 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
 \f
 ;;; Copy, move/rename, making hard and symbolic links
 
+(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.
 Special value `always' suppresses confirmation."
@@ -942,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
-                             (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)))))
@@ -951,10 +975,31 @@ Special value `always' suppresses confirmation."
 (defun dired-copy-file (from to ok-flag)
   (dired-handle-overwrite to)
   (condition-case ()
-      (copy-file from to ok-flag dired-copy-preserve-time)
+      (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)
   (dired-handle-overwrite to)
@@ -1062,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.
 
-;; 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
@@ -1138,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
-                                            &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))
-        (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
-                   (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)))))
-    (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.
@@ -1196,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)).
+;; 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)
-   (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.
@@ -1245,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.
 
+(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.
@@ -1252,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
-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 '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")
-                          arg dired-keep-marker-copy))
+                          arg dired-keep-marker-copy
+                          nil dired-copy-how-to-fn)))
 
 ;;;###autoload
 (defun dired-do-symlink (&optional arg)
@@ -1264,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
-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))
@@ -1275,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
-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))
@@ -1284,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.
-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"))
@@ -1299,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).
-  ;; 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))
@@ -1365,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)
-  "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.
-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)
@@ -1380,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)
-  "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"))
-  (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)
-  "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)
@@ -1399,8 +1504,8 @@ See function `dired-rename-regexp' for more info."
 
 ;;;###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)
@@ -1480,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)))
 
+;;;###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,
@@ -1512,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))
-    (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))))
 
@@ -1548,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)
-  ;;"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)
@@ -1618,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)
-    (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))
@@ -1645,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)
-  ;; 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
@@ -1792,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)
-       (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 ()
@@ -1886,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): ")
-  (tags-search regexp '(dired-get-marked-files)))
+  (tags-search regexp '(dired-get-marked-files nil nil 'dired-nondirectory-p)))
 
 ;;;###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.
-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")
-  (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
+;;;###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)