]> code.delx.au - gnu-emacs/blobdiff - lisp/dired-aux.el
*** empty log message ***
[gnu-emacs] / lisp / dired-aux.el
index a27e434b3df9bd2581de8e71188ece0aa42e28ed..0709e0cfe1ce340953d746d0b0b0783ebf877905 100644 (file)
@@ -1,6 +1,6 @@
 ;;; dired-aux.el --- less commonly used parts of dired  -*-byte-compile-dynamic: t;-*-
 
-;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001
+;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001, 2004
 ;;   Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
@@ -43,6 +43,9 @@
 ;;;###begin dired-cmd.el
 ;; Diffing and compressing
 
+(defconst dired-star-subst-regexp "\\(^\\|[ \t]\\)\\*\\([ \t]\\|$\\)")
+(defconst dired-quark-subst-regexp "\\(^\\|[ \t]\\)\\?\\([ \t]\\|$\\)")
+
 ;;;###autoload
 (defun dired-diff (file &optional switches)
   "Compare file at point with file FILE using `diff'.
@@ -85,8 +88,105 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'."
       nil))
   (diff-backup (dired-get-filename) switches))
 
+(defun dired-compare-directories (dir2 predicate)
+  "Mark files with different file attributes in two dired buffers.
+Compare file attributes of files in the current directory
+with file attributes in directory DIR2 using PREDICATE on pairs of files
+with the same name.  Mark files for which PREDICATE returns non-nil.
+Mark files with different names if PREDICATE is nil (or interactively
+when the user enters empty input at the predicate prompt).
+
+PREDICATE is a Lisp expression that can refer to the following variables:
+
+    size1, size2   - file size in bytes
+    mtime1, mtime2 - last modification time in seconds, as a float
+    fa1, fa2       - list of file attributes
+                     returned by function `file-attributes'
+
+    where 1 refers to attribute of file in the current dired buffer
+    and 2 to attribute of file in second dired buffer.
+
+Examples of PREDICATE:
+
+    (> mtime1 mtime2) - mark newer files
+    (not (= size1 size2)) - mark files with different sizes
+    (not (string= (nth 8 fa1) (nth 8 fa2))) - mark files with different modes
+    (not (and (= (nth 2 fa1) (nth 2 fa2))   - mark files with different UID
+              (= (nth 3 fa1) (nth 3 fa2))))   and GID."
+  (interactive
+   (list (read-file-name (format "Compare %s with: "
+                                (dired-current-directory))
+                        (dired-dwim-target-directory))
+         (read-from-minibuffer "Mark if (lisp expr or RET): " nil nil t nil "nil")))
+  (let* ((dir1 (dired-current-directory))
+         (file-alist1 (dired-files-attributes dir1))
+         (file-alist2 (dired-files-attributes dir2))
+        (file-list1 (mapcar
+                     'cadr
+                      (dired-file-set-difference
+                       file-alist1 file-alist2
+                      predicate)))
+        (file-list2 (mapcar
+                     'cadr
+                      (dired-file-set-difference
+                       file-alist2 file-alist1
+                      predicate))))
+    (dired-fun-in-all-buffers
+     dir1 nil
+     (lambda ()
+       (dired-mark-if
+        (member (dired-get-filename nil t) file-list1) nil)))
+    (dired-fun-in-all-buffers
+     dir2 nil
+     (lambda ()
+       (dired-mark-if
+        (member (dired-get-filename nil t) file-list2) nil)))
+    (message "Marked in dir1: %s files, in dir2: %s files"
+             (length file-list1)
+             (length file-list2))))
+
+(defun dired-file-set-difference (list1 list2 predicate)
+  "Combine LIST1 and LIST2 using a set-difference operation.
+The result list contains all file items that appear in LIST1 but not LIST2.
+This is a non-destructive function; it makes a copy of the data if necessary
+to avoid corrupting the original LIST1 and LIST2.
+PREDICATE (see `dired-compare-directories') is an additional match
+condition.  Two file items are considered to match if they are equal
+*and* PREDICATE evaluates to t."
+  (if (or (null list1) (null list2))
+      list1
+    (let (res)
+      (dolist (file1 list1)
+       (unless (let ((list list2))
+                 (while (and list
+                             (not (let* ((file2 (car list))
+                                         (fa1 (caddr file1))
+                                         (fa2 (caddr file2))
+                                         (size1 (nth 7 fa1))
+                                         (size2 (nth 7 fa2))
+                                         (mtime1 (float-time (nth 5 fa1)))
+                                         (mtime2 (float-time (nth 5 fa2))))
+                                    (and
+                                     (equal (car file1) (car file2))
+                                     (not (eval predicate))))))
+                   (setq list (cdr list)))
+                 list)
+         (setq res (cons file1 res))))
+      (nreverse res))))
+
+(defun dired-files-attributes (dir)
+  "Return a list of all file names and attributes from DIR.
+List has a form of (file-name full-file-name (attribute-list))"
+  (mapcar
+   (lambda (file-name)
+     (let ((full-file-name (expand-file-name file-name dir)))
+       (list file-name
+             full-file-name
+             (file-attributes full-file-name))))
+   (directory-files dir)))
+\f
 (defun dired-do-chxxx (attribute-name program op-symbol arg)
-  ;; Change file attributes (mode, group, owner) of marked files and
+  ;; Change file attributes (mode, group, owner, timestamp) of marked files and
   ;; refresh their file lines.
   ;; ATTRIBUTE-NAME is a string describing the attribute to the user.
   ;; PROGRAM is the program used to change the attribute.
@@ -102,8 +202,11 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'."
     (setq failures
          (dired-bunch-files 10000
                             (function dired-check-process)
-                            (append 
-                             (list operation program new-attribute)
+                            (append
+                             (list operation program)
+                             (if (eq op-symbol 'touch)
+                                 '("-t") nil)
+                             (list new-attribute)
                              (if (string-match "gnu" system-configuration)
                                  '("--") nil))
                             files))
@@ -136,12 +239,19 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
       (error "chown not supported on this system"))
   (dired-do-chxxx "Owner" dired-chown-program 'chown arg))
 
+(defun dired-do-touch (&optional arg)
+  "Change the timestamp of the marked (or next ARG) files.
+This calls touch."
+  (interactive "P")
+  (dired-do-chxxx "Timestamp" dired-touch-program 'touch arg))
+
 ;; Process all the files in FILES in batches of a convenient size,
 ;; by means of (FUNCALL FUNCTION ARGS... SOME-FILES...).
 ;; Batches are chosen to need less than MAX chars for the file names,
 ;; allowing 3 extra characters of separator per file name.
 (defun dired-bunch-files (max function args files)
   (let (pending
+       past
        (pending-length 0)
        failures)
     ;; Accumulate files as long as they fit in MAX chars,
@@ -153,9 +263,15 @@ This calls chmod, thus symbolic modes like `g+w' are allowed."
        ;; If we have at least 1 pending file
        ;; 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))
-                        failures)
+           (setq pending (nreverse pending)
+                 ;; The elements of PENDING are now in forward order.
+                 ;; Do the operation and record failures.
+                 failures (nconc (apply function (append args pending))
+                                 failures)
+                 ;; Transfer the elemens of PENDING onto PAST
+                 ;; and clear it out.  Now PAST contains the first N files
+                 ;; specified (for some N), and FILES contains the rest.
+                 past (nconc past pending)
                  pending nil
                  pending-length 0))
        ;; Do (setq pending (cons thisfile pending))
@@ -164,8 +280,12 @@ 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))
-          failures)))
+    (setq pending (nreverse pending))
+    (prog1
+       (nconc (apply function (append args pending))
+              failures)
+      ;; Now the original list FILES has been put back as it was.
+      (nconc past pending))))
 
 ;;;###autoload
 (defun dired-do-print (&optional arg)
@@ -316,22 +436,30 @@ 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 `?'.
 
-If there is no `*', but a `?' in the command then it is still run
-on each file individually but with the filename substituted there
-instead of at the end of the command.
+Otherwise, this runs COMMAND on each file individually with the
+file name added at the end of COMMAND (separated by a space).
 
-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.
+`*' 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 `*\"\"'.
 
-The shell command has the top level directory as working directory, so
-output files usually are created there instead of in a subdir.
+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."
@@ -347,18 +475,30 @@ the list of file names explicitly with the FILE-LIST argument."
                                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 dired-star-subst-regexp command)))
+        (subst (not (string-match dired-quark-subst-regexp 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 ((not (or on-each subst))
+              (error "You can not combine `*' and `?' substitution marks"))
+             ((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 ""
@@ -376,25 +516,23 @@ the list of file names explicitly with the FILE-LIST argument."
 ;; 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 * or a ?
-  ;; On the other hand, you can never accidentally get a * or a ? into
-  ;; your cmd.
   (let ((stuff-it
-        (cond ((string-match "\\*" command)
-               (function (lambda (x)
-                           (dired-replace-in-string "\\*" x command))))
-              ((string-match "\\?" command)
-               (function (lambda (x)
-                            (dired-replace-in-string "\\?" x command))))
-              (t (function (lambda (x) (concat command " " x)))))))
+        (if (or (string-match dired-star-subst-regexp command)
+                (string-match dired-quark-subst-regexp command))
+            (lambda (x)
+              (let ((retval command))
+                (while (string-match
+                        "\\(^\\|[ \t]\\)\\([*?]\\)\\([ \t]\\|$\\)" retval)
+                  (setq retval (replace-match x t t retval 2)))
+                retval))
+          (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)
@@ -434,8 +572,8 @@ the list of file names explicitly with the FILE-LIST argument."
       (set-buffer err-buffer)
       (erase-buffer)
       (setq default-directory dir      ; caller's default-directory
-           err (/= 0
-                (apply (function dired-call-process) program nil arguments)))
+           err (not (eq 0
+                (apply (function dired-call-process) program nil arguments))))
       (if err
          (progn
            (dired-log (concat program " " (prin1-to-string arguments) "\n"))
@@ -532,6 +670,8 @@ 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")
+    ("\\.dz\\'" "" "dictunzip")
+    ("\\.tbz\\'" ".tar" "bunzip2")
     ("\\.bz2\\'" "" "bunzip2")
     ;; This item controls naming for compression.
     ("\\.tar\\'" ".tgz" nil))
@@ -560,7 +700,7 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
            (setq suffix (car suffixes) suffixes nil))
        (setq suffixes (cdr suffixes))))
     ;; If so, compute desired new name.
-    (if suffix 
+    (if suffix
        (setq newname (concat (substring file 0 (match-beginning 0))
                              (nth 1 suffix))))
     (cond (handler
@@ -645,7 +785,7 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
   '((?\y . y) (?\040 . y)              ; `y' or SPC means accept once
     (?n . n) (?\177 . n)               ; `n' or DEL skips once
     (?! . yes)                         ; `!' accepts rest
-    (?q. no) (?\e . no)                        ; `q' or ESC skips rest
+    (?q . no) (?\e . no)               ; `q' or ESC skips rest
     ;; None of these keys quit - use C-g for that.
     ))
 
@@ -771,27 +911,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
@@ -825,7 +944,7 @@ 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))))
@@ -843,26 +962,34 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
            (let (buffer-read-only opoint)
              (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")))
+               (dired-insert-directory directory
+                                       (concat dired-actual-switches "d")
+                                       (list filename)))
+              (goto-char opoint)
+             ;; Put in desired marker char.
+             (when marker-char
+               (let ((dired-marker-char
+                      (if (integerp marker-char) marker-char dired-marker-char)))
+                 (dired-mark nil)))
              ;; Compensate for a bug in ange-ftp.
              ;; It inserts the file's absolute name, rather than
              ;; the relative one.  That may be hard to fix since it
              ;; is probably controlled by something in ftp.
-             (goto-char opoint)        
+             (goto-char opoint)
              (let ((inserted-name (dired-get-filename 'verbatim)))
                (if (file-name-directory inserted-name)
-                   (progn
+                   (let (props)
                      (end-of-line)
-                     (delete-char (- (length inserted-name)))
-                     (insert filename)
+                     (forward-char (- (length inserted-name)))
+                     (setq props (text-properties-at (point)))
+                     (delete-char (length inserted-name))
+                     (let ((pt (point)))
+                       (insert filename)
+                       (set-text-properties pt (point) props))
                      (forward-char 1))
                  (forward-line 1)))
-           ;; 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:
@@ -878,14 +1005,6 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
        (goto-char opoint))
     (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)
-  ;; two spaces or a marker plus a space:
-  (insert (if marker-char
-             (if (integerp marker-char) marker-char dired-marker-char)
-           ?\040)
-         ?\040))
-
 (defun dired-after-subdir-garbage (dir)
   ;; Return pos of first file line of DIR, skipping header and total
   ;; or wildcard lines.
@@ -915,6 +1034,7 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
 
 ;;;###autoload
 (defun dired-relist-file (file)
+  "Create or update the line for FILE in all Dired buffers it would belong in."
   (dired-fun-in-all-buffers (file-name-directory file)
                            (file-name-nondirectory file)
                            (function dired-relist-entry) file))
@@ -961,7 +1081,7 @@ Special value `always' suppresses confirmation."
 (defvar dired-overwrite-confirmed)
 
 (defun dired-handle-overwrite (to)
-  ;; Save old version of a to be overwritten file TO.
+  ;; Save old version of file TO that is to be overwritten.
   ;; `dired-overwrite-confirmed' and `overwrite-backup-query' are fluid vars
   ;; from dired-create-files.
   (let (backup)
@@ -1006,16 +1126,16 @@ Special value `always' suppresses confirmation."
     (copy-file from to ok-flag dired-copy-preserve-time)))
 
 ;;;###autoload
-(defun dired-rename-file (from to ok-flag)
-  (dired-handle-overwrite to)
-  (rename-file from to ok-flag)                ; error is caught in -create-files
+(defun dired-rename-file (file newname ok-if-already-exists)
+  (dired-handle-overwrite newname)
+  (rename-file file newname ok-if-already-exists) ; error is caught in -create-files
   ;; Silently rename the visited file of any buffer visiting this file.
-  (and (get-file-buffer from)
-       (with-current-buffer (get-file-buffer from)
-        (set-visited-file-name to nil t)))
-  (dired-remove-file from)
+  (and (get-file-buffer file)
+       (with-current-buffer (get-file-buffer file)
+        (set-visited-file-name newname nil t)))
+  (dired-remove-file file)
   ;; See if it's an inserted subdir, and rename that, too.
-  (dired-rename-subdir from to))
+  (dired-rename-subdir file newname))
 
 (defun dired-rename-subdir (from-dir to-dir)
   (setq from-dir (file-name-as-directory from-dir)
@@ -1246,7 +1366,7 @@ Optional arg HOW-TO is used to set the value of the into-dir variable
                          ;; 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))
+                         (if (and (memq system-type '(ms-dos windows-nt cygwin))
                                   (eq op-symbol 'move)
                                   dired-one-file
                                   (string= (downcase
@@ -1379,14 +1499,22 @@ 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)
+  (dired-do-create-files 'hardlink (function dired-hardlink)
                           "Hardlink" arg dired-keep-marker-hardlink))
 
+(defun dired-hardlink (file newname &optional ok-if-already-exists)
+  (dired-handle-overwrite newname)
+  ;; error is caught in -create-files
+  (add-name-to-file file newname ok-if-already-exists)
+  ;; Update the link count
+  (dired-relist-file file))
+
 ;;;###autoload
 (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.
+This command also renames any buffers that are visiting the files.
 The default suggested for the target directory depends on the value
 of `dired-dwim-target', which see."
   (interactive "P")
@@ -1397,13 +1525,13 @@ of `dired-dwim-target', which see."
 ;;; 5K
 ;;;###begin dired-re.el
 (defun dired-do-create-files-regexp
-  (file-creator operation arg regexp newname &optional whole-path marker-char)
+  (file-creator operation arg regexp newname &optional whole-name marker-char)
   ;; Create a new file for each marked file using regexps.
   ;; FILE-CREATOR and OPERATION as in dired-create-files.
   ;; 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 file name
+  ;; Optional arg WHOLE-NAME 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))
@@ -1416,7 +1544,7 @@ Type SPC or `y' to %s one match, DEL or `n' to skip to next,
                                          (downcase operation)))
         (regexp-name-constructor
          ;; Function to construct new filename using REGEXP and NEWNAME:
-         (if whole-path                ; easy (but rare) case
+         (if whole-name                ; easy (but rare) case
              (function
               (lambda (from)
                 (let ((to (dired-string-replace-match regexp from newname))
@@ -1431,7 +1559,7 @@ Type SPC or `y' to %s one match, DEL or `n' to skip to next,
                            to)
                     (dired-log "%s: %s did not match regexp %s\n"
                                operation from regexp)))))
-           ;; not whole-path, replace non-directory part only
+           ;; not whole-name, replace non-directory part only
            (function
             (lambda (from)
               (let* ((new (dired-string-replace-match
@@ -1454,21 +1582,21 @@ Type SPC or `y' to %s one match, DEL or `n' to skip to next,
 
 (defun dired-mark-read-regexp (operation)
   ;; Prompt user about performing OPERATION.
-  ;; Read and return list of: regexp newname arg whole-path.
-  (let* ((whole-path
+  ;; Read and return list of: regexp newname arg whole-name.
+  (let* ((whole-name
          (equal 0 (prefix-numeric-value current-prefix-arg)))
         (arg
-         (if whole-path nil current-prefix-arg))
+         (if whole-name nil current-prefix-arg))
         (regexp
          (dired-read-regexp
-          (concat (if whole-path "Path " "") operation " from (regexp): ")))
+          (concat (if whole-name "Abs. " "") operation " from (regexp): ")))
         (newname
          (read-string
-          (concat (if whole-path "Path " "") operation " " regexp " to: "))))
-    (list regexp newname arg whole-path)))
+          (concat (if whole-name "Abs. " "") operation " " regexp " to: "))))
+    (list regexp newname arg whole-name)))
 
 ;;;###autoload
-(defun dired-do-rename-regexp (regexp newname &optional arg whole-path)
+(defun dired-do-rename-regexp (regexp newname &optional arg whole-name)
   "Rename selected files whose names match REGEXP to NEWNAME.
 
 With non-zero prefix argument ARG, the command operates on the next ARG
@@ -1485,10 +1613,10 @@ 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)
-   "Rename" arg regexp newname whole-path dired-keep-marker-rename))
+   "Rename" arg regexp newname whole-name dired-keep-marker-rename))
 
 ;;;###autoload
-(defun dired-do-copy-regexp (regexp newname &optional arg whole-path)
+(defun dired-do-copy-regexp (regexp newname &optional arg whole-name)
   "Copy selected files whose names match REGEXP to NEWNAME.
 See function `dired-do-rename-regexp' for more info."
   (interactive (dired-mark-read-regexp "Copy"))
@@ -1496,25 +1624,25 @@ See function `dired-do-rename-regexp' for more info."
     (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)))
+     arg regexp newname whole-name dired-keep-marker-copy)))
 
 ;;;###autoload
-(defun dired-do-hardlink-regexp (regexp newname &optional arg whole-path)
+(defun dired-do-hardlink-regexp (regexp newname &optional arg whole-name)
   "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)
-   "HardLink" arg regexp newname whole-path dired-keep-marker-hardlink))
+   "HardLink" arg regexp newname whole-name dired-keep-marker-hardlink))
 
 ;;;###autoload
-(defun dired-do-symlink-regexp (regexp newname &optional arg whole-path)
+(defun dired-do-symlink-regexp (regexp newname &optional arg whole-name)
   "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)
-   "SymLink" arg regexp newname whole-path dired-keep-marker-symlink))
+   "SymLink" arg regexp newname whole-name dired-keep-marker-symlink))
 
 (defun dired-create-files-non-directory
   (file-creator basename-constructor operation arg)
@@ -1707,34 +1835,21 @@ With optional arg REMEMBER-MARKS, return an alist of marked files."
       (delete-region begin-marker (point)))))
 
 (defun dired-insert-subdir-doinsert (dirname switches)
-  ;; Insert ls output after point and put point on the correct
-  ;; position for the subdir alist.
+  ;; Insert ls output after point.
   ;; Return the boundary of the inserted text (as list of BEG and END).
-  (let ((begin (point)) end)
-    (message "Reading directory %s..." dirname)
-    (let ((dired-actual-switches
-          (or switches
-              (dired-replace-in-string "R" "" dired-actual-switches))))
-      (if (equal dirname (car (car (reverse dired-subdir-alist))))
-         ;; top level directory may contain wildcards:
-         (dired-readin-insert dired-directory)
-       (let ((opoint (point)))
-         (insert-directory dirname dired-actual-switches nil t)
-         (dired-insert-set-properties opoint (point)))))
-    (message "Reading directory %s...done" dirname)
-    (setq end (point-marker))
-    (indent-rigidly begin end 2)
-    ;;  call dired-insert-headerline afterwards, as under VMS dired-ls
-    ;;  does insert the headerline itself and the insert function just
-    ;;  moves point.
-    ;;  Need a marker for END as this inserts text.
-    (goto-char begin)
-    (if (not (looking-at "^  /.*:$"))
-       (dired-insert-headerline dirname))
-    ;; point is now like in dired-build-subdir-alist
-    (prog1
-       (list begin (marker-position end))
-      (set-marker end nil))))
+  (save-excursion
+    (let ((begin (point)))
+      (message "Reading directory %s..." dirname)
+      (let ((dired-actual-switches
+            (or switches
+                (dired-replace-in-string "R" "" dired-actual-switches))))
+       (if (equal dirname (car (car (last dired-subdir-alist))))
+           ;; If doing the top level directory of the buffer,
+           ;; redo it as specified in dired-directory.
+           (dired-readin-insert)
+         (dired-insert-directory dirname dired-actual-switches nil nil t)))
+      (message "Reading directory %s...done" dirname)
+      (list begin (point)))))
 
 (defun dired-insert-subdir-doupdate (dirname elt beg-end)
   ;; Point is at the correct subdir alist position for ELT,
@@ -1998,7 +2113,7 @@ 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-regexp (from to &optional delimited)
@@ -2008,22 +2123,32 @@ 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)))
+  (dolist (file (dired-get-marked-files nil nil 'dired-nondirectory-p))
+    (let ((buffer (get-file-buffer file)))
+      (if (and buffer (with-current-buffer buffer
+                       buffer-read-only))
+         (error "File `%s' is visited read-only" file))))
+  (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." 
+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 
+  (with-temp-buffer
     (if deref-symlinks
-       (call-process "file" nil t t "-L" file)
-      (call-process "file" nil t t file))
+       (call-process "file" nil t t "-L" "--" file)
+      (call-process "file" nil t t "--" file))
     (when (bolp)
       (backward-delete-char 1))
-    (message (buffer-string))))
+    (message "%s" (buffer-string))))
 
 (provide 'dired-aux)
 
+;;; arch-tag: 4b508de9-a153-423d-8d3f-a1bbd86f4f60
 ;;; dired-aux.el ends here