]> code.delx.au - gnu-emacs/blobdiff - lisp/dired-aux.el
*** empty log message ***
[gnu-emacs] / lisp / dired-aux.el
index 05d998176f75b6fbcdd427984a6f2a5a91124465..0709e0cfe1ce340953d746d0b0b0783ebf877905 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, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1992, 1994, 1998, 2000, 2001, 2004
+;;   Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
 ;; Maintainer: FSF
+;; Keywords: files
 
 ;; This file is part of GNU Emacs.
 
 ;;;###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'.
-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'."
@@ -82,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.
@@ -100,7 +203,10 @@ With prefix arg, prompt for argument SWITCHES which is options for `diff'."
          (dired-bunch-files 10000
                             (function dired-check-process)
                             (append
-                             (list operation program new-attribute)
+                             (list operation program)
+                             (if (eq op-symbol 'touch)
+                                 '("-t") nil)
+                             (list new-attribute)
                              (if (string-match "gnu" system-configuration)
                                  '("--") nil))
                             files))
@@ -122,7 +228,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,15 +236,22 @@ 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))
 
+(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,
@@ -150,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))
@@ -161,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)
@@ -198,7 +321,7 @@ Uses the shell command coming from variables `lpr-command' and
    nil op-symbol files
    (function read-string)
    (format prompt (dired-mark-prompt arg files)) initial))
-
+\f
 ;;; Cleaning a directory: flagging some backups for deletion.
 
 (defvar dired-file-version-alist)
@@ -290,7 +413,7 @@ with a prefix argument."
         (progn (beginning-of-line)
                (delete-char 1)
                (insert dired-del-marker)))))
-
+\f
 ;;; Shell commands
 
 (defun dired-read-shell-command (prompt arg files)
@@ -313,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.
+
+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 `?'.
+
+Otherwise, this runs COMMAND on each file individually with the
+file name added at the end of COMMAND (separated by a space).
 
-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.
+`*' 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 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 att the end of the command.
+If COMMAND produces output, it goes to a separate buffer.
 
-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.
+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.
 
-The shell command has the top level directory as working directory, so
-output files usually are created there instead of in a subdir.
+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."
@@ -344,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 ""
@@ -373,23 +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)
-               (lambda (x) (replace-regexp-in-string "\\*" x command)))
-              ((string-match "\\?" command)
-               (lambda (x) (replace-regexp-in-string "\\?" x command)))
-              (t (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)
@@ -400,7 +543,7 @@ the list of file names explicitly with the FILE-LIST argument."
       (shell-command command)))
   ;; Return nil for sake of nconc in dired-bunch-files.
   nil)
-
+\f
 ;; In Emacs 19 this will return program's exit status.
 ;; This is a separate function so that ange-ftp can redefine it.
 (defun dired-call-process (program discard &rest arguments)
@@ -429,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"))
@@ -439,7 +582,7 @@ the list of file names explicitly with the FILE-LIST argument."
        (kill-buffer err-buffer)
        (message "%s...done" msg)
        nil))))
-
+\f
 ;; Commands that delete or redisplay part of the dired buffer.
 
 (defun dired-kill-line (&optional arg)
@@ -449,7 +592,7 @@ the list of file names explicitly with the FILE-LIST argument."
     (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)))
@@ -498,7 +641,7 @@ and use this command with a prefix argument (the value does not matter)."
        count))))
 
 ;;;###end dired-cmd.el
-
+\f
 ;;; 30K
 ;;;###begin dired-cp.el
 
@@ -527,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))
@@ -589,7 +734,7 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
                                            "compress" "-f" file))
                  ;; Don't use NEWNAME with `compress'.
                  (concat file ".Z"))))))))
-
+\f
 (defun dired-mark-confirm (op-symbol arg)
   ;; Request confirmation from the user that the operation described
   ;; by OP-SYMBOL is to be performed on the marked files.
@@ -640,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.
     ))
 
@@ -674,7 +819,7 @@ Otherwise, the rule is a compression rule, and compression is done with gzip.")
               (apply 'message qprompt qs-args)
               (setq char (set qs-var (read-char))))
             (memq (cdr elt) '(t y yes)))))))
-
+\f
 ;;;###autoload
 (defun dired-do-compress (&optional arg)
   "Compress or uncompress marked (or next ARG) files."
@@ -747,7 +892,7 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
                          arg)
     (dired-move-to-filename)
     (message "Redisplaying...done")))
-
+\f
 (defun dired-update-file-line (file)
   ;; Delete the current line, and insert an entry for FILE.
   ;; If FILE is nil, then just delete the current line.
@@ -766,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
@@ -820,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))))
@@ -838,11 +962,17 @@ 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
@@ -850,14 +980,16 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
              (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:
@@ -873,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.
@@ -910,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))
@@ -929,12 +1054,12 @@ a prefix arg lets you edit the `ls' switches used for the new listing."
                          (save-excursion (forward-line 1) (point))))
       (setq file (directory-file-name file))
       (dired-add-entry file (if (eq ?\040 marker) nil marker)))))
-
+\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.
+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."
@@ -956,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)
@@ -1001,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)
@@ -1026,7 +1151,7 @@ Special value `always' suppresses confirmation."
        (if (and buffer-file-name
                 (dired-in-this-tree buffer-file-name expanded-from-dir))
            (let ((modflag (buffer-modified-p))
-                 (to-file (replace-regexp-in-string
+                 (to-file (dired-replace-in-string
                            (concat "^" (regexp-quote from-dir))
                            to-dir
                            buffer-file-name)))
@@ -1085,8 +1210,8 @@ Special value `always' suppresses confirmation."
       ;; Update buffer-local dired-subdir-alist
       (setcar elt
              (dired-normalize-subdir
-              (replace-regexp-in-string regexp newtext (car elt)))))))
-
+              (dired-replace-in-string regexp newtext (car elt)))))))
+\f
 ;; The basic function for half a dozen variations on cp/mv/ln/ln -s.
 (defun dired-create-files (file-creator operation fn-list name-constructor
                                        &optional marker-char)
@@ -1181,14 +1306,15 @@ ESC or `q' to not overwrite any of the remaining files,
       (message "%s: %s file%s"
               operation success-count (dired-plural-s success-count)))))
   (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.
+  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'.
@@ -1240,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
@@ -1302,7 +1428,7 @@ Optional arg HOW-TO is used to set the value of the into-dir variable
                                 (dired-current-directory)))))
          (or other-dir this-dir))
       this-dir)))
-
+\f
 ;;;###autoload
 (defun dired-create-directory (directory)
   "Create a directory called DIRECTORY."
@@ -1330,7 +1456,7 @@ Optional arg HOW-TO is used to set the value of the into-dir variable
 ;; symlinks.
 
 (defvar dired-copy-how-to-fn nil
-  "Nil or a function used by `dired-do-copy' to determine target.
+  "nil or a function used by `dired-do-copy' to determine target.
 See HOW-TO argument for `dired-do-create-files'.")
 
 ;;;###autoload
@@ -1340,7 +1466,9 @@ 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")
   (let ((dired-recursive-copies dired-recursive-copies))
     (dired-do-create-files 'copy (function dired-copy-file)
@@ -1354,7 +1482,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))
@@ -1365,31 +1495,43 @@ 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)
+  (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."
+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")
   (dired-do-create-files 'move (function dired-rename-file)
                         "Move" arg dired-keep-marker-rename "Rename"))
 ;;;###end dired-cp.el
-
+\f
 ;;; 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))
@@ -1402,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))
@@ -1417,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
@@ -1440,22 +1582,27 @@ 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)
-  "Rename marked files containing REGEXP to NEWNAME.
+(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
+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'.
@@ -1466,36 +1613,36 @@ 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)
-  "Copy all marked files containing REGEXP to NEWNAME.
+(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"))
   (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)))
+     arg regexp newname whole-name dired-keep-marker-copy)))
 
 ;;;###autoload
-(defun dired-do-hardlink-regexp (regexp newname &optional arg whole-path)
-  "Hardlink all marked files containing REGEXP to NEWNAME.
+(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)
-  "Symlink all marked files containing REGEXP to NEWNAME.
+(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)
@@ -1542,7 +1689,7 @@ Type SPC or `y' to %s one file, DEL or `n' to skip to next,
   (dired-rename-non-directory (function downcase) "Rename downcase" arg))
 
 ;;;###end dired-re.el
-
+\f
 ;;; 13K
 ;;;###begin dired-ins.el
 
@@ -1604,7 +1751,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))))
 
@@ -1688,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
-              (replace-regexp-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,
@@ -1798,7 +1932,7 @@ is always equal to STRING."
        (setq result
              (cons (substring str end) result)))
     (nreverse result)))
-
+\f
 ;;; moving by subdirectories
 
 ;;;###autoload
@@ -1841,7 +1975,7 @@ The next char is either \\n, or \\r if DIR is hidden."
         ;; at either \r or \n after this function succeeds.
         (progn (skip-chars-forward "^\r\n")
                (point)))))
-
+\f
 ;;;###autoload
 (defun dired-mark-subdir-files ()
   "Mark all files except `.' and `..' in current subdirectory.
@@ -1885,7 +2019,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 ()
@@ -1903,7 +2037,7 @@ Lower levels are unaffected."
     (if pos
        (goto-char pos)
       (error "At the bottom"))))
-
+\f
 ;;; hiding
 
 (defun dired-unhide-subdir ()
@@ -1970,7 +2104,7 @@ Use \\[dired-hide-subdir] to (un)hide a particular subdirectory."
 
 ;;;###end dired-ins.el
 
-
+\f
 ;; Functions for searching in tags style among marked files.
 
 ;;;###autoload
@@ -1979,18 +2113,27 @@ 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)
   "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)))
-
+  (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.
@@ -1999,12 +2142,13 @@ 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))
+       (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