Fix a bug in the state cache mechanism. Refactor this a bit.
[emacs.git] / lisp / locate.el
blob804260969ee8188d608ca05cb0371a3d7d9dfea9
1 ;;; locate.el --- interface to the locate command
3 ;; Copyright (C) 1996, 1998, 2001-2013 Free Software Foundation, Inc.
5 ;; Author: Peter Breton <pbreton@cs.umb.edu>
6 ;; Keywords: unix files
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23 ;;; Commentary:
25 ;; Search a database of files and use dired commands on the result.
27 ;; Locate.el provides an interface to a program which searches a
28 ;; database of file names. By default, this program is the GNU locate
29 ;; command, but it could also be the BSD-style find command, or even a
30 ;; user specified command.
32 ;; To use the BSD-style "fast find", or any other shell command of the
33 ;; form
35 ;; SHELLPROGRAM Name-to-find
37 ;; set the variable `locate-command' in your init file.
39 ;; To use a more complicated expression, create a function which
40 ;; takes a string (the name to find) as input and returns a list.
41 ;; The first element should be the command to be executed, the remaining
42 ;; elements should be the arguments (including the name to find). Then put
44 ;; (setq locate-make-command-line 'my-locate-command-line)
46 ;; in your .emacs, using the name of your function in place of
47 ;; my-locate-command-line.
49 ;; You should make sure that whichever command you use works correctly
50 ;; from a shell prompt. GNU locate and BSD find expect the file databases
51 ;; to either be in standard places or located via environment variables.
52 ;; If the latter, make sure these environment variables are set in
53 ;; your emacs process.
55 ;; Locate-mode assumes that each line output from the locate-command
56 ;; consists exactly of a file name, possibly preceded or trailed by
57 ;; whitespace. If your file database has other information on the line (for
58 ;; example, the file size), you will need to redefine the function
59 ;; `locate-get-file-positions' to return a list consisting of the first
60 ;; character in the file name and the last character in the file name.
62 ;; To use locate-mode, simply type M-x locate and then the string
63 ;; you wish to find. You can use almost all of the dired commands in
64 ;; the resulting *Locate* buffer. It is worth noting that your commands
65 ;; do not, of course, affect the file database. For example, if you
66 ;; compress a file in the locate buffer, the actual file will be
67 ;; compressed, but the entry in the file database will not be
68 ;; affected. Consequently, the database and the filesystem will be out
69 ;; of sync until the next time the database is updated.
71 ;; The command `locate-with-filter' keeps only lines matching a
72 ;; regular expression; this is often useful to constrain a big search.
75 ;;;;; Building a database of files ;;;;;;;;;
77 ;; You can create a simple files database with a port of the Unix find command
78 ;; and one of the various Windows NT various scheduling utilities,
79 ;; for example the AT command from the NT Resource Kit, WinCron which is
80 ;; included with Microsoft FrontPage, or the shareware NTCron program.
82 ;; To set up a function which searches the files database, do something
83 ;; like this:
85 ;; (defvar locate-fcodes-file "c:/users/peter/fcodes")
86 ;; (defvar locate-make-command-line 'nt-locate-make-command-line)
88 ;; (defun nt-locate-make-command-line (arg)
89 ;; (list "grep" "-i" arg locate-fcodes-file))
91 ;;;;;;;; ADVICE For dired-make-relative: ;;;;;;;;;
93 ;; For certain dired commands to work right, you should also include the
94 ;; following in your _emacs/.emacs:
96 ;; (defadvice dired-make-relative (before set-no-error activate)
97 ;; "For locate mode and Windows, don't return errors"
98 ;; (if (and (eq major-mode 'locate-mode)
99 ;; (memq system-type '(windows-nt ms-dos)))
100 ;; (ad-set-arg 2 t)
101 ;; ))
103 ;; Otherwise, `dired-make-relative' will give error messages like
104 ;; "FILENAME: not in directory tree growing at /"
107 ;;; Code:
109 (require 'dired)
111 ;; Variables
113 (defvar locate-current-filter nil)
114 (defvar locate-local-filter nil)
115 (defvar locate-local-search nil)
116 (defvar locate-local-prompt nil)
118 (defgroup locate nil
119 "Interface to the locate command."
120 :prefix "locate-"
121 :group 'external)
123 (defcustom locate-command "locate"
124 "Executable program for searching a database of files.
125 The Emacs commands `locate' and `locate-with-filter' use this.
126 The value should be a program that can be called from a shell
127 with one argument, SEARCH-STRING. The program determines which
128 database it searches. The output of the program should consist
129 of those file names in the database that match SEARCH-STRING,
130 listed one per line, possibly with leading or trailing
131 whitespace. If the output is in another form, you may have to
132 redefine the function `locate-get-file-positions'.
134 The program may interpret SEARCH-STRING as a literal string, a
135 shell pattern or a regular expression. The exact rules of what
136 constitutes a match may also depend on the program.
138 The standard value of this variable is \"locate\".
139 This program normally searches a database of all files on your
140 system, or of all files that you have access to. Consult the
141 documentation of that program for the details about how it determines
142 which file names match SEARCH-STRING. (Those details vary highly with
143 the version.)"
144 :type 'string
145 :group 'locate)
147 (defcustom locate-post-command-hook nil
148 "List of hook functions run after `locate' (see `run-hooks')."
149 :type 'hook
150 :group 'locate)
152 (defvar locate-history-list nil
153 "The history list used by the \\[locate] command.")
155 (defvar locate-grep-history-list nil
156 "The history list used by the \\[locate-with-filter] command.")
158 (defcustom locate-make-command-line 'locate-default-make-command-line
159 "Function used to create the locate command line.
160 The Emacs commands `locate' and `locate-with-filter' use this.
161 This function should take one argument, a string (the name to find)
162 and return a list of strings. The first element of the list should be
163 the name of a command to be executed by a shell, the remaining elements
164 should be the arguments to that command (including the name to find)."
165 :type 'function
166 :group 'locate)
168 (defcustom locate-buffer-name "*Locate*"
169 "Name of the buffer to show results from the \\[locate] command."
170 :type 'string
171 :group 'locate)
173 (defcustom locate-fcodes-file nil
174 "File name for the database of file names used by `locate'.
175 If non-nil, `locate' uses this name in the header of the `*Locate*'
176 buffer. If nil, it mentions no file name in that header.
178 Just setting this variable does not actually change the database
179 that `locate' searches. The executive program that the Emacs
180 function `locate' uses, as given by the variables `locate-command'
181 or `locate-make-command-line', determines the database."
182 :type '(choice (const :tag "None" nil) file)
183 :group 'locate)
185 (defcustom locate-header-face nil
186 "Face used to highlight the locate header."
187 :type '(choice (const :tag "None" nil) face)
188 :group 'locate)
190 ;;;###autoload
191 (defcustom locate-ls-subdir-switches (purecopy "-al")
192 "`ls' switches for inserting subdirectories in `*Locate*' buffers.
193 This should contain the \"-l\" switch, but not the \"-F\" or \"-b\" switches."
194 :type 'string
195 :group 'locate
196 :version "22.1")
198 (defcustom locate-update-when-revert nil
199 "This option affects how the *Locate* buffer gets reverted.
200 If non-nil, offer to update the locate database when reverting that buffer.
201 \(Normally, you need to have root privileges for this to work. See the
202 option `locate-update-path'.)
203 If nil, reverting does not update the locate database."
204 :type 'boolean
205 :group 'locate
206 :version "22.1")
208 (defcustom locate-update-command "updatedb"
209 "The executable program used to update the locate database."
210 :type 'string
211 :group 'locate)
213 (defcustom locate-update-path "/"
214 "The default directory from where `locate-update-command' is called.
215 Usually, root permissions are required to run that command. This
216 can be achieved by setting this option to \"/su::\" or \"/sudo::\"
217 \(if you have the appropriate authority). If your current user
218 permissions are sufficient to run the command, you can set this
219 option to \"/\"."
220 :type 'string
221 :group 'locate
222 :version "22.1")
224 (defcustom locate-prompt-for-command nil
225 "If non-nil, the `locate' command prompts for a command to run.
226 Otherwise, that behavior is invoked via a prefix argument.
228 Setting this option non-nil actually inverts the meaning of a prefix arg;
229 that is, with a prefix arg, you get the default behavior."
230 :group 'locate
231 :type 'boolean)
233 (defcustom locate-mode-hook nil
234 "List of hook functions run by `locate-mode' (see `run-mode-hooks')."
235 :type 'hook
236 :group 'locate)
238 ;; Functions
240 (defun locate-default-make-command-line (search-string)
241 (list locate-command search-string))
243 (defun locate-word-at-point ()
244 (let ((pt (point)))
245 (buffer-substring-no-properties
246 (save-excursion
247 (skip-chars-backward "-a-zA-Z0-9.")
248 (point))
249 (save-excursion
250 (skip-chars-forward "-a-zA-Z0-9.")
251 (skip-chars-backward "." pt)
252 (point)))))
254 ;; Function for use in interactive declarations.
255 (defun locate-prompt-for-search-string ()
256 (if (or (and current-prefix-arg
257 (not locate-prompt-for-command))
258 (and (not current-prefix-arg) locate-prompt-for-command))
259 (let ((locate-cmd (funcall locate-make-command-line "")))
260 (read-from-minibuffer
261 "Run locate (like this): "
262 (cons
263 (concat (car locate-cmd) " "
264 (mapconcat 'identity (cdr locate-cmd) " "))
265 (+ 2 (length (car locate-cmd))))
266 nil nil 'locate-history-list))
267 (let* ((default (locate-word-at-point))
268 (input
269 (read-from-minibuffer
270 (if (> (length default) 0)
271 (format "Locate (default %s): " default)
272 (format "Locate: "))
273 nil nil nil 'locate-history-list default t)))
274 (and (equal input "") default
275 (setq input default))
276 input)))
278 ;;;###autoload
279 (defun locate (search-string &optional filter arg)
280 "Run the program `locate', putting results in `*Locate*' buffer.
281 Pass it SEARCH-STRING as argument. Interactively, prompt for SEARCH-STRING.
282 With prefix arg ARG, prompt for the exact shell command to run instead.
284 This program searches for those file names in a database that match
285 SEARCH-STRING and normally outputs all matching absolute file names,
286 one per line. The database normally consists of all files on your
287 system, or of all files that you have access to. Consult the
288 documentation of the program for the details about how it determines
289 which file names match SEARCH-STRING. (Those details vary highly with
290 the version.)
292 You can specify another program for this command to run by customizing
293 the variables `locate-command' or `locate-make-command-line'.
295 The main use of FILTER is to implement `locate-with-filter'. See
296 the docstring of that function for its meaning.
298 After preparing the results buffer, this runs `dired-mode-hook' and
299 then `locate-post-command-hook'."
300 (interactive
301 (list
302 (locate-prompt-for-search-string)
304 current-prefix-arg))
306 (if (equal search-string "")
307 (error "Please specify a filename to search for"))
308 (let* ((locate-cmd-list (funcall locate-make-command-line search-string))
309 (locate-cmd (car locate-cmd-list))
310 (locate-cmd-args (cdr locate-cmd-list))
311 (run-locate-command
312 (or (and arg (not locate-prompt-for-command))
313 (and (not arg) locate-prompt-for-command))))
315 ;; Find the Locate buffer
316 (save-window-excursion
317 (set-buffer (get-buffer-create locate-buffer-name))
318 (locate-mode)
319 (let ((inhibit-read-only t)
320 (buffer-undo-list t))
321 (erase-buffer)
323 (setq locate-current-filter filter)
324 (set (make-local-variable 'locate-local-search) search-string)
325 (set (make-local-variable 'locate-local-filter) filter)
326 (set (make-local-variable 'locate-local-prompt) run-locate-command)
328 (if run-locate-command
329 (shell-command search-string locate-buffer-name)
330 (apply 'call-process locate-cmd nil t nil locate-cmd-args))
332 (and filter
333 (locate-filter-output filter))
335 (locate-do-setup search-string)))
336 (and (not (string-equal (buffer-name) locate-buffer-name))
337 (pop-to-buffer locate-buffer-name))
339 (run-hooks 'dired-mode-hook)
340 (dired-next-line 3) ;move to first matching file.
341 (run-hooks 'locate-post-command-hook)))
343 ;;;###autoload
344 (defun locate-with-filter (search-string filter &optional arg)
345 "Run the executable program `locate' with a filter.
346 This function is similar to the function `locate', which see.
347 The difference is that, when invoked interactively, the present function
348 prompts for both SEARCH-STRING and FILTER. It passes SEARCH-STRING
349 to the locate executable program. It produces a `*Locate*' buffer
350 that lists only those lines in the output of the locate program that
351 contain a match for the regular expression FILTER; this is often useful
352 to constrain a big search.
354 ARG is the interactive prefix arg, which has the same effect as in `locate'.
356 When called from Lisp, this function is identical with `locate',
357 except that FILTER is not optional."
358 (interactive
359 (list
360 (locate-prompt-for-search-string)
361 (read-from-minibuffer "Filter: " nil nil
362 nil 'locate-grep-history-list)
363 current-prefix-arg))
364 (locate search-string filter arg))
366 (defun locate-filter-output (filter)
367 "Filter output from the locate command."
368 (goto-char (point-min))
369 (keep-lines filter))
371 (defvar locate-mode-map
372 (let ((map (copy-keymap dired-mode-map)))
373 ;; Undefine Useless Dired Menu bars
374 (define-key map [menu-bar Dired] 'undefined)
375 (define-key map [menu-bar subdir] 'undefined)
376 (define-key map [menu-bar mark executables] 'undefined)
377 (define-key map [menu-bar mark directory] 'undefined)
378 (define-key map [menu-bar mark directories] 'undefined)
379 (define-key map [menu-bar mark symlinks] 'undefined)
380 (define-key map [M-mouse-2] 'locate-mouse-view-file)
381 (define-key map "\C-c\C-t" 'locate-tags)
382 (define-key map "l" 'locate-do-redisplay)
383 (define-key map "U" 'dired-unmark-all-files)
384 (define-key map "V" 'locate-find-directory)
385 map)
386 "Local keymap for Locate mode buffers.")
388 ;; This variable is used to indent the lines and then to search for
389 ;; the file name
390 (defconst locate-filename-indentation 4
391 "The amount of indentation for each file.")
393 (defun locate-get-file-positions ()
394 "Return list of start and end of the file name on the current line.
395 This is a list of two buffer positions.
397 You should only call this function on lines that contain a file name
398 listed by the locate program. Inside inserted subdirectories, or if
399 there is no file name on the current line, the return value is
400 meaningless. You can check whether the current line contains a file
401 listed by the locate program, using the function
402 `locate-main-listing-line-p'."
403 (list (+ locate-filename-indentation
404 (line-beginning-position))
405 ;; Assume names end at the end of the line.
406 (line-end-position)))
408 ;; From SQL-mode
409 (defun locate-current-line-number ()
410 "Return the current line number, as an integer."
411 (+ (count-lines (point-min) (point))
412 (if (eq (current-column) 0)
414 0)))
416 ;; You should only call this function on lines that contain a file name
417 ;; listed by the locate program. Inside inserted subdirectories, or if
418 ;; there is no file name on the current line, the return value is
419 ;; meaningless. You can check whether the current line contains a file
420 ;; listed by the locate program, using the function
421 ;; `locate-main-listing-line-p'.
422 (defun locate-get-filename ()
423 (let ((pos (locate-get-file-positions))
424 (lineno (locate-current-line-number)))
425 (and (not (eq lineno 1))
426 (not (eq lineno 2))
427 (buffer-substring (elt pos 0) (elt pos 1)))))
429 (defun locate-main-listing-line-p ()
430 "Return t if current line contains a file name listed by locate.
431 This function returns nil if the current line either contains no
432 file name or is inside a subdirectory."
433 (save-excursion
434 (forward-line 0)
435 (looking-at (concat "."
436 (make-string (1- locate-filename-indentation) ?\s)
437 "\\(/\\|[A-Za-z]:\\)"))))
439 (defun locate-mouse-view-file (event)
440 "In Locate mode, view a file, using the mouse."
441 (interactive "@e")
442 (save-excursion
443 (goto-char (posn-point (event-start event)))
444 (if (locate-main-listing-line-p)
445 (view-file (locate-get-filename))
446 (message "This command only works inside main listing."))))
448 ;; Define a mode for locate
449 ;; Default directory is set to "/" so that dired commands, which
450 ;; expect to be in a tree, will work properly
451 (defun locate-mode ()
452 "Major mode for the `*Locate*' buffer made by \\[locate].
453 \\<locate-mode-map>\
454 In that buffer, you can use almost all the usual dired bindings.
455 \\[locate-find-directory] visits the directory of the file on the current line.
456 This function runs `locate-mode-hook' before returning.
458 Operating on listed files works, but does not always
459 automatically update the buffer as in ordinary Dired.
460 This is true both for the main listing and for subdirectories.
461 Reverting the buffer using \\[revert-buffer] deletes all subdirectories.
462 Specific `locate-mode' commands, such as \\[locate-find-directory],
463 do not work in subdirectories.
465 \\{locate-mode-map}"
466 ;; Not to be called interactively.
467 (kill-all-local-variables)
468 ;; Avoid clobbering this variable
469 (make-local-variable 'dired-subdir-alist)
470 (use-local-map locate-mode-map)
471 (setq major-mode 'locate-mode
472 mode-name "Locate"
473 default-directory "/"
474 buffer-read-only t
475 selective-display t)
476 (dired-alist-add-1 default-directory (point-min-marker))
477 (set (make-local-variable 'dired-directory) "/")
478 (set (make-local-variable 'dired-subdir-switches) locate-ls-subdir-switches)
479 (setq dired-switches-alist nil)
480 (make-local-variable 'directory-listing-before-filename-regexp)
481 ;; This should support both Unix and Windoze style names
482 (setq directory-listing-before-filename-regexp
483 (concat "^.\\("
484 (make-string (1- locate-filename-indentation) ?\s)
485 "\\)\\|"
486 (default-value 'directory-listing-before-filename-regexp)))
487 (make-local-variable 'dired-actual-switches)
488 (setq dired-actual-switches "")
489 (make-local-variable 'dired-permission-flags-regexp)
490 (setq dired-permission-flags-regexp
491 (concat "^.\\("
492 (make-string (1- locate-filename-indentation) ?\s)
493 "\\)\\|"
494 (default-value 'dired-permission-flags-regexp)))
495 (make-local-variable 'revert-buffer-function)
496 (setq revert-buffer-function 'locate-update)
497 (set (make-local-variable 'page-delimiter) "\n\n")
498 (run-mode-hooks 'locate-mode-hook))
500 (defun locate-do-setup (search-string)
501 (goto-char (point-min))
502 (save-excursion
504 ;; Nothing returned from locate command?
505 (and (eobp)
506 (progn
507 (kill-buffer locate-buffer-name)
508 (if locate-current-filter
509 (error "Locate: no match for %s in database using filter %s"
510 search-string locate-current-filter)
511 (error "Locate: no match for %s in database" search-string))))
513 (locate-insert-header search-string)
515 (while (not (eobp))
516 (insert-char ?\s locate-filename-indentation t)
517 (locate-set-properties)
518 (forward-line 1)))
519 (goto-char (point-min)))
521 (defun locate-set-properties ()
522 (save-excursion
523 (let ((pos (locate-get-file-positions)))
524 (dired-insert-set-properties (elt pos 0) (elt pos 1)))))
526 (defun locate-insert-header (search-string)
527 ;; There needs to be a space before `Matches, because otherwise,
528 ;; `*!" would erase the `M'. We can not use two spaces, or the line
529 ;; would mistakenly fit `dired-subdir-regexp'.
530 (let ((locate-format-string " /:\n Matches for %s")
531 (locate-regexp-match
532 (concat " *Matches for \\(" (regexp-quote search-string) "\\)"))
533 (locate-format-args (list search-string))
536 (and locate-fcodes-file
537 (setq locate-format-string
538 (concat locate-format-string " in %s")
539 locate-regexp-match
540 (concat locate-regexp-match
541 " in \\("
542 (regexp-quote locate-fcodes-file)
543 "\\)")
544 locate-format-args
545 (append (list locate-fcodes-file) locate-format-args)))
547 (and locate-current-filter
548 (setq locate-format-string
549 (concat locate-format-string " using filter %s")
550 locate-regexp-match
551 (concat locate-regexp-match
552 " using filter "
553 "\\("
554 (regexp-quote locate-current-filter)
555 "\\)")
556 locate-format-args
557 (append (list locate-current-filter) locate-format-args)))
559 (setq locate-format-string
560 (concat locate-format-string ":\n\n")
561 locate-regexp-match
562 (concat locate-regexp-match ":\n"))
564 (insert (apply 'format locate-format-string (reverse locate-format-args)))
566 (save-excursion
567 (goto-char (point-min))
568 (forward-line 1)
569 (if (not (looking-at locate-regexp-match))
571 (add-text-properties (match-beginning 1) (match-end 1)
572 (list 'face locate-header-face))
573 (and (match-beginning 2)
574 (add-text-properties (match-beginning 2) (match-end 2)
575 (list 'face locate-header-face)))
576 (and (match-beginning 3)
577 (add-text-properties (match-beginning 3) (match-end 3)
578 (list 'face locate-header-face)))
579 ))))
581 (defun locate-tags ()
582 "Visit a tags table in `*Locate*' mode."
583 (interactive)
584 (if (locate-main-listing-line-p)
585 (let ((tags-table (locate-get-filename)))
586 (and (y-or-n-p (format "Visit tags table %s? " tags-table))
587 (visit-tags-table tags-table)))
588 (message "This command only works inside main listing.")))
590 ;; From Stephen Eglen <stephen@cns.ed.ac.uk>
591 (defun locate-update (_ignore1 _ignore2)
592 "Revert the *Locate* buffer.
593 If `locate-update-when-revert' is non-nil, offer to update the
594 locate database using the shell command in `locate-update-command'."
595 (let ((locate-buffer-name (buffer-name))
596 (locate-prompt-for-command locate-local-prompt))
597 (and locate-update-when-revert
598 (yes-or-no-p "Update locate database (may take a few seconds)? ")
599 ;; `expand-file-name' is used in order to autoload Tramp if
600 ;; necessary. It cannot be loaded when `default-directory'
601 ;; is remote.
602 (let ((default-directory (expand-file-name locate-update-path)))
603 (shell-command locate-update-command)))
604 (locate locate-local-search locate-local-filter)))
606 ;;; Modified three functions from `dired.el':
607 ;;; dired-find-directory,
608 ;;; dired-find-directory-other-window
609 ;;; dired-get-filename
611 (defun locate-find-directory ()
612 "Visit the directory of the file mentioned on this line."
613 (interactive)
614 (if (locate-main-listing-line-p)
615 (let ((directory-name (locate-get-dirname)))
616 (if (file-directory-p directory-name)
617 (find-file directory-name)
618 (if (file-symlink-p directory-name)
619 (error "Directory is a symlink to a nonexistent target")
620 (error "Directory no longer exists; run `updatedb' to update database"))))
621 (message "This command only works inside main listing.")))
623 (defun locate-find-directory-other-window ()
624 "Visit the directory of the file named on this line in other window."
625 (interactive)
626 (if (locate-main-listing-line-p)
627 (find-file-other-window (locate-get-dirname))
628 (message "This command only works inside main listing.")))
630 ;; You should only call this function on lines that contain a file name
631 ;; listed by the locate program. Inside inserted subdirectories, or if
632 ;; there is no file name on the current line, the return value is
633 ;; meaningless. You can check whether the current line contains a file
634 ;; listed by the locate program, using the function
635 ;; `locate-main-listing-line-p'.
636 (defun locate-get-dirname ()
637 "Return the directory name of the file mentioned on this line."
638 (let (file (filepos (locate-get-file-positions)))
639 (if (setq file (buffer-substring (nth 0 filepos) (nth 1 filepos)))
640 (progn
641 ;; Get rid of the mouse-face property that file names have.
642 (set-text-properties 0 (length file) nil file)
643 (setq file (file-name-directory file))
644 ;; Unquote names quoted by ls or by dired-insert-directory.
645 ;; Using read to unquote is much faster than substituting
646 ;; \007 (4 chars) -> ^G (1 char) etc. in a lisp loop.
647 (setq file
648 (read
649 (concat "\""
650 ;; some ls -b don't escape quotes, argh!
651 ;; This is not needed for GNU ls, though.
652 (or (dired-string-replace-match
653 "\\([^\\]\\|\\`\\)\"" file "\\1\\\\\"" nil t)
654 file)
655 "\"")))))
656 (and file buffer-file-coding-system
657 (not file-name-coding-system)
658 (setq file (encode-coding-string file buffer-file-coding-system)))
659 file))
661 ;; Only for GNU locate
662 (defun locate-in-alternate-database (search-string database)
663 "Run the GNU locate program, using an alternate database.
665 This command only works if you use GNU locate. It does not work
666 properly if `locate-prompt-for-command' is set to t. In that
667 case, you can just run the regular `locate' command and specify
668 the database on the command line."
669 (interactive
670 (list
671 (progn
672 ;; (require 'locate)
673 (read-from-minibuffer "Locate: " nil nil
674 nil 'locate-history-list))
675 (read-file-name "Locate using Database: " )
677 (or (file-exists-p database)
678 (error "Database file %s does not exist" database))
679 (let ((locate-make-command-line
680 (function (lambda (string)
681 (cons locate-command
682 (list (concat "--database="
683 (expand-file-name database))
684 string))))))
685 (locate search-string)))
687 (defun locate-do-redisplay (&optional arg test-for-subdir)
688 "Like `dired-do-redisplay', but adapted for `*Locate*' buffers."
689 (interactive "P\np")
690 (if (string= (dired-current-directory) "/")
691 (message "This command only works in subdirectories.")
692 (let ((dired-actual-switches locate-ls-subdir-switches))
693 (dired-do-redisplay arg test-for-subdir))))
695 (provide 'locate)
697 ;;; locate.el ends here