diff --git a/emacs.spec b/emacs.spec
index 71e51e0..db6b433 100644
--- a/emacs.spec
+++ b/emacs.spec
@@ -6,7 +6,7 @@
 Summary: GNU Emacs text editor
 Name: emacs
 Version: 21.4
-Release: 2
+Release: 3
 License: GPL
 URL: http://www.gnu.org/software/emacs/
 Group: Applications/Editors
@@ -36,6 +36,8 @@ Source27: rfc1345.el
 Source28: http://ftp.gnu.org/gnu/tramp/tramp-%{tramp_ver}.tar.gz
 Source29: tramp-init.el
 Source30: wrapper
+Source31: igrep.el
+Source32: igrep-init.el
 Buildroot: %{_tmppath}/%{name}-%{version}-root
 BuildRequires: glibc-devel, gcc, bzip2, ncurses-devel, zlib-devel, autoconf213
 Buildrequires: xorg-x11-devel, Xaw3d-devel, libpng-devel, libjpeg-devel, libungif-devel, libtiff-devel
@@ -197,7 +199,7 @@ rm lisp/finder-inf.el lisp/play/tetris.el*
 
 # install rest of site-lisp files
 ( cd site-lisp
-  cp %SOURCE7 %SOURCE8 %SOURCE13 %SOURCE20 %SOURCE21 .
+  cp %SOURCE7 %SOURCE8 %SOURCE13 %SOURCE20 %SOURCE21 %SOURCE31 .
   # xemacs compat patch for rpm-spec-mode
   patch < %SOURCE18
   # fix po-auto-replace-revision-date nil
@@ -403,6 +405,9 @@ fi
 %defattr(-,root,root)
 
 %changelog
+* Wed Apr 20 2005 Jens Petersen <petersen@redhat.com> - 21.4-3
+- add igrep.el and init file
+
 * Mon Apr 11 2005 Jens Petersen <petersen@redhat.com> - 21.4-2
 - update etags to 17.11 (idht4n@hotmail.com, 151390)
   - add etags-14.21-17.11-diff.patch
diff --git a/igrep-init.el b/igrep-init.el
new file mode 100644
index 0000000..331a7ec
--- /dev/null
+++ b/igrep-init.el
@@ -0,0 +1,16 @@
+;; igrep-init.el
+
+(autoload 'igrep "igrep"
+  "*Run `grep` PROGRAM to match REGEX in FILES..." t)
+(autoload 'igrep-find "igrep"
+  "*Run `grep` via `find`..." t)
+(autoload 'igrep-visited-files "igrep"
+  "*Run `grep` ... on all visited files." t)
+(autoload 'dired-do-igrep "igrep"
+  "*Run `grep` on the marked (or next prefix ARG) files." t)
+(autoload 'dired-do-igrep-find "igrep"
+  "*Run `grep` via `find` on the marked (or next prefix ARG) directories." t)
+(autoload 'Buffer-menu-igrep "igrep"
+  "*Run `grep` on the files visited in buffers marked with '>'." t)
+(autoload 'igrep-insinuate "igrep"
+  "Define `grep' aliases for the corresponding `igrep' commands." t)
diff --git a/igrep.el b/igrep.el
new file mode 100644
index 0000000..db74b13
--- /dev/null
+++ b/igrep.el
@@ -0,0 +1,1153 @@
+;;; igrep.el --- An improved interface to `grep` and `find`
+;;; -*-unibyte: t;-*-
+
+;; Copyright � 1993-1998,2000-2004 Kevin Rodgers
+
+;; Author: Kevin Rodgers <ihs_4664@yahoo.com>
+;; Created:  22 Jun 1993
+;; Version: 2.112
+;; Keywords: tools, processes, search
+;; SCCS: @(#)igrep.el	2.112
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of
+;; the License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be
+;; useful, but WITHOUT ANY WARRANTY; without even the implied
+;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+;; PURPOSE.  See the GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+;; MA 02111-1307 USA
+
+;;; Commentary:
+
+;; The `igrep' command is like `grep' except that it takes three
+;; required arguments (PROGRAM, REGEX, and FILES) and an optional
+;; argument (OPTIONS) instead of just one argument (COMMAND).  The
+;; analogous `egrep' and `fgrep' commands are also defined for
+;; convenience.
+;; 
+;; The `igrep-find' command is like `igrep' except that it uses `find`
+;; to recursively `grep` a directory.  The analogous `egrep-find' and
+;; `fgrep-find' commands are also defined for convenience.
+;; 
+;; When called interactively, `igrep' and `igrep-find' (and their
+;; analogues) provide defaults for the REGEX and FILES arguments based
+;; on the current word and the visited file name (if the `igrep-regex-
+;; default' and `igrep-files-default' options are set, respectively).
+;; The `igrep-insert-default-key' option allows the default value to be
+;; inserted into the minibuffer for editing; since Emacs 20 provides
+;; that via the minibuffer history, it's only enabled for older
+;; versions by default. Other options that control the user interface
+;; are `igrep-insert-default-directory', `igrep-read-options', `igrep-
+;; read-multiple-files', `igrep-verbose-prompts', `igrep-save-buffers',
+;; and `igrep-menu-bar'.
+;; 
+;; Besides the basic `igrep-program' and `igrep-find-program' global
+;; variables, other variables control the syntax of the `grep` and
+;; `find` shell commands that are executed: `igrep-options', `igrep-
+;; regex-option', `igrep-case-fold-search', `igrep-find-prune-clause',
+;; `igrep-find-file-clause', and `igrep-find-use-xargs'.
+;; 
+;; The `igrep-use-zgrep' user option controls whether the corresponding
+;; GNU (gzip) "zPROGRAM" script is used, to `grep` compressed files.
+;; Special minibuffer history lists are maintained for the REGEX and
+;; FILES arguments.
+;; 
+;; The `agrep' and `agrep-find' commands are interfaces to the
+;; approximate `grep` utility, which is distributed with the `glimpse'
+;; indexing and query tool (available from http://www.tgries.de/agrep/).
+;; 
+;; `grep' itself can be advised to provide the `igrep' interface when
+;; it is invoked interactively (but still use the original argument
+;; list when it is called from Emacs Lisp), via the `igrep-insinuate'
+;; command.  `igrep-insinuate' also defines `grep-find' as an alias for
+;; `igrep-find', `dired-do-grep' and `dired-do-grep-find' as aliases
+;; for `dired-do-igrep' and `dired-do-igrep-find', and `Buffer-menu-
+;; grep' as an alias for `Buffer-menu-igrep'.
+;; 
+;; When run interactively from Dired mode, the various `igrep' commands
+;; provide defaults for the REGEX and FILES arguments that are based on
+;; the visited directory (including any inserted subdirectories) and
+;; the current file.  The alternative `dired-do-igrep' and `dired-do-
+;; igrep-find' commands respect the `dired-do-*' command conventions: a
+;; prefix argument is interpreted as the number of succeeding files to
+;; `grep`, otherwise all the marked files are `grep`ed.
+;; 
+;; The `igrep-visited-files' command provides a simple way to `grep`
+;; just those files that are being visited in buffers.  The `Buffer-
+;; menu-igrep' command does the same thing, for buffers marked for
+;; selection in Buffer Menu mode.
+
+;; Installation:
+;; 
+;; 1. Put this file in a directory that is a member of load-path, and
+;;    byte-compile it (e.g. with `M-x byte-compile-file') for better
+;;    performance.  You can ignore any warnings about references to free
+;;    variables and "not known to be defined" functions.
+;; 2. Put these forms in default.el or ~/.emacs:
+;;    (autoload 'igrep "igrep"
+;;       "*Run `grep` PROGRAM to match REGEX in FILES..." t)
+;;    (autoload 'igrep-find "igrep"
+;;       "*Run `grep` via `find`..." t)
+;;    (autoload 'igrep-visited-files "igrep"
+;;       "*Run `grep` ... on all visited files." t)
+;;    (autoload 'dired-do-igrep "igrep"
+;;       "*Run `grep` on the marked (or next prefix ARG) files." t)
+;;    (autoload 'dired-do-igrep-find "igrep"
+;;       "*Run `grep` via `find` on the marked (or next prefix ARG) directories." t)
+;;    (autoload 'Buffer-menu-igrep "igrep"
+;;      "*Run `grep` on the files visited in buffers marked with '>'." t)
+;;    (autoload 'igrep-insinuate "igrep"
+;;      "Define `grep' aliases for the corresponding `igrep' commands." t)
+;; 2. a. For completeness, you can add these forms as well:
+;;    (autoload 'grep "igrep"
+;;       "*Run `grep` PROGRAM to match REGEX in FILES..." t)
+;;    (autoload 'egrep "igrep"
+;;       "*Run `egrep`..." t)
+;;    (autoload 'fgrep "igrep"
+;;       "*Run `fgrep`..." t)
+;;    (autoload 'agrep "igrep"
+;;       "*Run `agrep`..." t)
+;;    (autoload 'grep-find "igrep"
+;;       "*Run `grep` via `find`..." t)
+;;    (autoload 'egrep-find "igrep"
+;;       "*Run `egrep` via `find`..." t)
+;;    (autoload 'fgrep-find "igrep"
+;;       "*Run `fgrep` via `find`..." t)
+;;    (autoload 'agrep-find "igrep"
+;;       "*Run `agrep` via `find`..." t)
+;; 3. If you are running Windows 95/NT, you should install findutils
+;;    and grep from release 17.1 (or higher) of the Cygnus GNU-Win32
+;;    distribution (http://www.cygnus.com/misc/gnu-win32/).
+
+;; Usage:
+;; 
+;; These igrep commands accept 1, 2, or 3 `C-u' prefix arguments:
+;; 	M-x igrep		M-x igrep-find
+;; 	M-x  grep		M-x  grep-find	[after `M-x igrep-insinuate']
+;; 	M-x egrep		M-x egrep-find
+;; 	M-x fgrep		M-x fgrep-find
+;; 	M-x agrep		M-x agrep-find
+;; 
+;; These igrep commands accept a single `C-u' prefix argument:
+;; 	M-x igrep-visited-files
+;; 	M-x Buffer-menu-igrep	[in the *Buffer List* buffer]
+;; 
+;; These igrep commands interpret a prefix argument like the Emacs
+;; `dired-do-*' commands:
+;; 	M-x dired-do-igrep	M-x dired-do-igrep-find
+;; 	M-x  dired-do-grep	M-x  dired-do-grep-find	[after `M-x
+;; 							 igrep-insinuate']
+;; 
+;; These Emacs commands can be used after any igrep command:
+;; 	C-x ` (M-x next-error)
+;; 	C-c C-c (M-x compile-goto-error)	[in the *igrep* buffer]
+
+;; Customization examples:
+;; 
+;; To ignore case by default:
+;; 	(setq igrep-options "-i")
+;; or:
+;; 	(setq igrep-case-fold-search t)
+;; To search subdirectories by default:
+;; 	(setq igrep-find t)
+;; To search files with the GNU (gzip) zgrep script:
+;; 	(setq igrep-use-zgrep t)
+;; or define new igrep commands (this works for zegrep and zfgrep as well):
+;; 	(igrep-define zgrep)		; M-x zgrep
+;; 	(igrep-find-define zgrep)	; M-x zgrep-find
+;; To search "*.[ch]" files by default in C mode:
+;; 	(put 'igrep-files-default 'c-mode
+;; 	     (lambda () "*.[ch]"))
+;; To disable the default search regex and/or files pattern, except for
+;; specific modes:
+;; 	(setq igrep-regex-default 'ignore)
+;; 	(setq igrep-files-default 'ignore)
+;; To avoid exceeding some shells' limit on command argument length
+;; (this only searches files in the current directory):
+;; 	(setq igrep-find t
+;; 	      igrep-find-prune-clause "-type d \\! -name .")
+
+;; To do:
+;; 1. Replace igrep-options with a table that maps igrep-program
+;;    to the appropriate options, and/or support POSIX (egrep -> `grep -E`).
+;; 2. Generalize support for the -prune find clause (e.g. -fstype nfs).
+;; 3. Provide support for `glimpse`.
+
+;;; Code:
+
+;; Package interface:
+
+(require 'custom)			; defgroup, defcustom
+
+(require 'easymenu)			; easy-menu-define, easy-menu-add-item
+
+(or (condition-case nil
+	(require 'grep)			; CVS Emacs (21.3.50/21.4)
+      (error nil))
+    (require 'compile))			; compile-internal, grep-regexp-alist,
+					; grep-null-device
+
+(eval-when-compile
+  (require 'dired)			; dired-directory,
+					; dired-get-filename,
+					; dired-current-directory,
+					; dired-get-marked-files,
+					; dired-mark-get-files
+  (or (featurep 'ange-ftp)
+      (featurep 'efs)
+      (condition-case nil
+	  (load-library "ange-ftp")	; ange-ftp-ftp-name
+	(error nil))
+      (condition-case nil
+	  (load-library "efs")		; efs-ftp-path
+	(error nil)))
+  )
+
+(defconst igrep-version "2.112"
+  "This version of igrep.el.")
+
+(defgroup igrep nil
+  "An improved interface to `grep` and `find`."
+  :group 'compilation)
+
+;; User options:
+
+(defcustom igrep-options nil
+  "*The options passed by `\\[igrep]' to `igrep-program', or nil.
+
+\"-n\" will automatically be passed to `igrep-program', to generate the
+output expected by `\\[next-error]' and `\\[compile-goto-error]'.
+\"-e\" will automatically be passed to `igrep-program', if it supports
+that option."
+  :group 'igrep
+  :type '(choice (const nil) (string)))
+(put 'igrep-options 'variable-interactive
+     "xOptions (\"-xyz\" or nil): ")
+
+(defcustom igrep-case-fold-search nil
+  "*If non-nil, `\\[igrep]' ignores case unless REGEX has uppercase letters."
+  :group 'igrep
+  :type '(boolean))
+(put 'igrep-case-fold-search 'variable-interactive
+     "XIgnore case? (t or nil): ")
+
+(defcustom igrep-read-options nil
+  "*If non-nil, `\\[igrep]' always prompts for options;
+otherwise, it only prompts when 1 or 3 `C-u's are given as a prefix arg."
+  :group 'igrep
+  :type '(boolean))
+(put 'igrep-read-options 'variable-interactive
+     "XAlways prompt for options? (t or nil): ")
+
+(defcustom igrep-read-multiple-files nil
+  "*If non-nil, `\\[igrep]' always prompts for multiple-files;
+otherwise, it only prompts when 2 or 3 `C-u's are given as a prefix arg."
+  :group 'igrep
+  :type '(boolean))
+(put 'igrep-read-multiple-files 'variable-interactive
+     "XAlways prompt for multiple files? (t or nil): ")
+
+(defcustom igrep-regex-default 'current-word
+  "*If non-nil, a function that returns a default REGEX for `\\[igrep]'.
+The function is called with no arguments and should return a string (or nil).
+
+A different function can be specified for any particular mode by specifying
+a value for that `major-mode' property; for example:
+	(put 'igrep-regex-default 'dired-mode
+	     'igrep-dired-file-current-word)"
+  :group 'igrep
+  :type '(choice (const nil) (function)))
+(put 'igrep-regex-default 'variable-interactive
+     "SProvide a default regex? (function or nil): ")
+(put 'igrep-regex-default 'dired-mode
+     'igrep-dired-file-current-word)
+
+(defcustom igrep-files-default 'igrep-buffer-file-name-pattern
+  "*If non-nil, a function that returns the default FILES for `\\[igrep]'.
+The function is called with no arguments and should return a string,
+or a list of strings (or nil).
+
+A different function can be specified for any particular mode by specifying
+a value for that `major-mode' property; for example:
+	(put 'igrep-files-default 'dired-mode
+	     'igrep-dired-directory-file-pattern)"
+  :group 'igrep
+  :type '(choice (const nil) (function)))
+(put 'igrep-files-default 'variable-interactive
+     "SProvide a default file name pattern? (function or nil): ")
+(put 'igrep-files-default 'dired-mode
+     'igrep-dired-directory-file-pattern)
+
+(defcustom igrep-verbose-prompts t
+  "*If t, `\\[igrep]' prompts for arguments verbosely;
+if not t but non-nil, `\\[igrep]' prompts for arguments semi-verbosely;
+if nil, `\\[igrep]' prompts for arguments tersely."
+  :group 'igrep
+  :type '(choice (const :tag "Verbose" t)
+		 (other :tag "Semi-verbose" semi)
+		 (const :tag "Terse" nil)))
+(put 'igrep-verbose-prompts 'variable-interactive
+     "XPrompt verbosely? (t, 'semi, or nil): ")
+
+(defcustom igrep-insert-default-directory nil
+  "*The value of `insert-default-directory' for `\\[igrep]'."
+  :group 'igrep
+  :type '(boolean))
+(put 'igrep-insert-default-directory 'variable-interactive
+     "XPrompt with directory in the minibuffer? (t or nil): ")
+
+(defcustom igrep-insert-default-key
+  (if (< emacs-major-version 20) "\C-c\C-e")
+  "*The key used to insert the default argument in the minibuffer.
+In Emacs 20, the default is available via the minibuffer history \
+\(\\<minibuffer-local-map>\\[next-history-element])."
+  :group 'igrep
+  :type '(choice (const nil) (string) (vector))) ; key-binding
+(put 'igrep-insert-default-key 'variable-interactive
+     "kSet key to insert the default `\\[igrep]' argument in the minibuffer: ")
+
+(defcustom igrep-save-buffers 'query
+  "*If t, `\\[igrep]' first saves each modified file buffer;
+if not t but non-nil, `\\[igrep]' offers to save each modified file buffer."
+  :group 'igrep
+  :type '(choice (const :tag "Save" t)
+		 (other :tag "Query" query)
+		 (const :tag "Don't Save" nil)))
+(put 'igrep-save-buffers 'variable-interactive
+     "XSave modified buffers? (t, 'query, or nil): ")
+
+(defcustom igrep-menu-bar t
+  "*If non-nil, enable the `igrep-menu' submenu on the \"Tools\" menu bar."
+  :group 'igrep
+  :type '(boolean))
+(put 'igrep-menu-bar 'variable-interactive
+     "XEnable menu bar? (t or nil): ")
+
+;; User variables:
+
+(defsubst igrep-easy-menu-item (name callback help-keyword help-text)
+  "Return a [NAME CALLBACK HELP-KEYWORD HELP-TEXT] menu item.
+See `easy-menu-define'."
+  (if (featurep 'xemacs)                ; no :help keyword
+      (vector name callback)
+    (vector name callback help-keyword help-text)))
+
+(defvar :help ':help)			; Emacs 19
+
+(defvar igrep-easy-menu
+  `("Search Files and Directories (igrep)"
+    ,@(cond ((featurep 'xemacs) '(:included igrep-menu-bar))
+	    ((>= emacs-major-version 20) '(:active igrep-menu-bar))
+	    (t ()))
+    ("Search files"
+     ,(igrep-easy-menu-item "`grep` files..." 'igrep
+                            :help "Search files for basic regex(5)s")
+     ,(igrep-easy-menu-item "`egrep` files..." 'egrep
+                            :help "Search files for extended regex(5)s")
+     ,(igrep-easy-menu-item "`fgrep` files..." 'fgrep
+                            :help "Search files for strings"))
+    ("Search directories"
+     ,(igrep-easy-menu-item "`find | grep` directories..." 'igrep-find
+                            :help "Search directories for basic regex(5)s")
+     ,(igrep-easy-menu-item "`find | egrep` directories..." 'egrep-find
+                            :help "Search directories for extended regex(5)s")
+     ,(igrep-easy-menu-item "`find | fgrep` directories..." 'fgrep-find
+                            :help "Search directories for strings"))
+    "--"
+    ,(igrep-easy-menu-item "Search visited files..." 'igrep-visited-files
+                           :help "Search visited files for basic regex(5)s"))
+  "If non-nil, the menu bar submenu of `igrep' commands.
+See `easy-menu-define'.")
+
+(defvar igrep-null-device
+  (cond ((boundp 'null-device) null-device) ; Emacs 20
+	((boundp 'grep-null-device) grep-null-device)) ; Emacs 19
+  "The system null device.")
+
+(defvar igrep-program "grep"
+  "The default program run by `\\[igrep]' and `\\[igrep-find]'.
+It must accept a `grep` regex argument and one or more file names, plus
+the \"-n\" option.  If nil, `\\[igrep]' prompts for the program to run.")
+
+(defvar igrep-regex-option
+  (if (equal (call-process igrep-program nil nil nil
+			   "-e" "foo" igrep-null-device)
+	     1)
+      "-e")
+  "If non-nil, the option used to specify the REGEX argument to `\\[igrep]'.
+This protects an initial \"-\" from option processing.")
+
+(defvar igrep-program-table		; referenced by igrep-use-zgrep
+  (let ((exec-directories exec-path)
+	(program-obarray (make-vector 11 0)))
+    (while exec-directories
+      (if (and (car exec-directories)
+	       (file-directory-p (car exec-directories))
+	       (file-readable-p (car exec-directories)))
+	  (let ((grep-programs
+		 (directory-files (car exec-directories)
+				  nil "grep\\(\\.exe\\)?\\'")))
+	    (while grep-programs
+	      ;; Check `(file-executable-p (car grep-programs))'?
+	      (if (save-match-data
+		    (string-match "\\.exe\\'" (car grep-programs)))
+		  (intern (substring (car grep-programs) 0 -4) program-obarray)
+		(intern (car grep-programs) program-obarray))
+	      (setq grep-programs (cdr grep-programs)))))
+      (setq exec-directories (cdr exec-directories)))
+    program-obarray)
+  "An obarray of available `grep` programs.
+This is passed by `igrep-read-program' to `completing-read' when
+`igrep-program' is nil.")
+
+(defvar igrep-use-zgrep
+  (if (intern-soft "zgrep" igrep-program-table)
+      'files)
+  "If t, `\\[igrep]' searches files using the GNU (gzip) `zPROGRAM` script;
+If not t but non-nil, `\\[igrep]' searches compressed FILES using `zPROGRAM`;
+if nil, `\\[igrep]' searches files with `PROGRAM`.")
+
+(defvar igrep-find nil
+  "If non-nil, `\\[igrep]' searches directories using `find`.
+See `igrep-find'.")
+
+(defvar igrep-find-program "find"
+  "The program run by `\\[igrep-find]'.")
+
+(defvar igrep-find-prune-clause
+  (if (equal (call-process igrep-find-program nil nil nil
+			   igrep-null-device "-prune")
+	     0)
+      (format "-type d %s -name RCS -o -name CVS -o -name SCCS %s"
+	      (shell-quote-argument "(")
+	      (shell-quote-argument ")")))
+  "The `find` clause used to prune directories, or nil;
+see `igrep-find'.")
+
+(defvar igrep-find-file-clause
+  (format "-type f %s -name %s %s -name %s %s -name %s %s -name %s" ; -type l
+	  (shell-quote-argument "!")
+	  (shell-quote-argument "*~")	; Emacs backup
+	  (shell-quote-argument "!")
+	  (shell-quote-argument "*,v")	; RCS file
+	  (shell-quote-argument "!")
+	  (shell-quote-argument "s.*")	; SCCS file
+	  (shell-quote-argument "!")
+	  (shell-quote-argument ".#*"))	; CVS file
+  "The `find` clause used to filter files passed to `grep`, or nil;
+see `igrep-find'.")
+
+(defvar igrep-find-use-xargs
+  (cond ((equal (call-process igrep-find-program nil nil nil
+			      igrep-null-device "-print0")
+		0)
+	 'gnu)
+	((not (equal system-type 'darwin)))) ; not MacOS
+  "Whether `\\[igrep-find]' uses the `xargs` program or not.
+If `gnu', it executes
+	`find ... -print0 | xargs -0 -e grep ...`;
+if not `gnu' but non-nil, it executes
+	`find ... -print | xargs -e grep ...`;
+if nil, it executes
+	`find ... -exec grep ...`.")
+
+(defvar igrep-program-default "grep"
+  "The default `grep` program.
+This is passed by `igrep-read-program' to `completing-read' when
+`igrep-program' is nil.")
+
+;; Internal variables:
+
+(defvar igrep-regex-history '()
+  "The minibuffer history list for `\\[igrep]'s REGEX argument.")
+
+(defvar igrep-files-history '()
+  "The minibuffer history list for `\\[igrep]'s FILES argument.")
+
+;; Commands:
+
+;;;###autoload
+(defun igrep-insinuate (&optional override)
+  "Define `grep' aliases for the corresponding `igrep' commands.
+With a prefix arg, OVERRIDE the current `grep' command definitions."
+  (interactive "P")
+  (if override
+      (defalias 'grep 'igrep)
+    (defadvice grep (around igrep-interactive first (&rest command-args)
+			    activate)
+      "If called interactively, use the `\\[igrep]' interface instead,
+where COMMAND-ARGS is (PROGRAM REGEX FILES [OPTIONS]); if called
+programmatically, COMMAND-ARGS is still (COMMAND)."
+      (interactive (igrep-read-args))
+      (if (interactive-p)
+	  (apply 'igrep command-args)
+	ad-do-it)))
+  (if (or (not (fboundp 'grep-find))
+	  override)
+      (defalias 'grep-find 'igrep-find))
+  (if (or (not (fboundp 'dired-do-grep))
+	  override)
+      (defalias 'dired-do-grep 'dired-do-igrep))
+  (if (or (not (fboundp 'dired-do-grep-find))
+	  override)
+      (defalias 'dired-do-grep-find 'dired-do-igrep-find))
+  (if (or (not (fboundp 'Buffer-menu-grep))
+	  override)
+      (defalias 'Buffer-menu-grep 'Buffer-menu-igrep)))
+
+(defsubst igrep-quote-file-name (file)
+  "Quote FILE name pattern for `shell-file-name'."
+  (if (fboundp 'shell-quote-wildcard-pattern) ; Emacs 21
+      (shell-quote-wildcard-pattern file)
+    (shell-quote-argument file)))
+
+;;;###autoload
+(defun igrep (program regex files &optional options)
+  "*Run `grep` PROGRAM to match REGEX in FILES.
+The output is displayed in the *igrep* buffer, which `\\[next-error]' and
+`\\[compile-goto-error]' parse to find each line of matched text.
+
+PROGRAM may be nil, in which case it defaults to `igrep-program'.
+
+REGEX is automatically quoted by `shell-quote-argument'.
+
+FILES is either a file name pattern (automatically quoted by
+`shell-quote-wildcard-pattern', then expanded by the `shell-file-name' shell),
+or a list of file name patterns.
+
+Optional OPTIONS is also passed to PROGRAM; it defaults to `igrep-options'.
+
+If a prefix argument \
+\(`\\[universal-argument]') \
+is given when called interactively,
+or if `igrep-read-options' is set, OPTIONS is read from the minibuffer.
+
+If two prefix arguments \
+\(`\\[universal-argument] \\[universal-argument]') \
+are given when called interactively,
+or if `igrep-read-multiple-files' is set, FILES is read from the minibuffer
+multiple times.
+
+If three prefix arguments \
+\(`\\[universal-argument] \\[universal-argument] \\[universal-argument]') \
+are given when called interactively,
+or if `igrep-read-options' and `igrep-read-multiple-files' are set,
+OPTIONS is read and FILES is read multiple times.
+
+If `igrep-find' is non-nil, the directory or directories
+containing FILES is recursively searched for files whose name matches
+the file name component of FILES (and whose contents match REGEX)."
+  (interactive
+   (igrep-read-args))
+  (if (null program)
+      (setq program (or igrep-program "grep")))
+  (if (null options)
+      (setq options igrep-options))
+  (if (not (listp files))		; (stringp files)
+      (setq files (list files)))
+  (if (and (member ?~ (mapcar 'string-to-char files))
+	   (save-match-data
+	     (string-match "\\`[rj]?sh\\(\\.exe\\)?\\'"
+			   (file-name-nondirectory shell-file-name))))
+      ;; (restricted, job-control, or standard) Bourne shell doesn't expand ~:
+      (setq files
+	    (mapcar 'expand-file-name files)))
+  (let* ((use-zgrep (cond ((eq igrep-use-zgrep t))
+			  (igrep-use-zgrep
+			   (let ((files files)
+				 (compressed-p nil))
+			     (while (and files (not compressed-p))
+			       (if (save-match-data
+				     (string-match "\\.g?[zZ]\\'" (car files)))
+				   (setq compressed-p t))
+			       (setq files (cdr files)))
+			     compressed-p))
+			  (t nil)))
+	 (command (format "%s -n %s %s %s %s %s"
+			  (if (and use-zgrep
+				   (save-match-data
+				     (not (string-match "\\`z" program))))
+			      (setq program (concat "z" program))
+			    program)
+			  (or options
+			      (and igrep-case-fold-search
+				   (equal regex (downcase regex))
+				   "-i")
+			      "")
+			  (or igrep-regex-option
+			      (progn
+				(if (save-match-data
+				      (string-match "\\`-" regex))
+				    (setq regex (concat "\\" regex)))
+				""))
+			  (shell-quote-argument regex)
+			  (if igrep-find
+			      (if igrep-find-use-xargs
+				  ""
+				(shell-quote-argument "{}"))
+			    (mapconcat (lambda (file)
+					 (let ((dir (file-name-directory file)))
+					   (if dir
+					       (expand-file-name
+						(file-name-nondirectory file)
+						(igrep-quote-file-name dir))
+					     file)))
+				       files " "))
+			  igrep-null-device)))
+    (if igrep-find
+	(setq command
+	      (igrep-format-find-command command files)))
+    (cond ((eq igrep-save-buffers t) (save-some-buffers t))
+	  (igrep-save-buffers (save-some-buffers)))
+    (if (fboundp 'compilation-start)    ; CVS Emacs (21.3.50/21.4)
+        (let ((compilation-process-setup-function 'grep-process-setup))
+          (or (fboundp 'igrep-mode)
+              (define-derived-mode igrep-mode grep-mode "Igrep"))
+          (compilation-start command
+                             'igrep-mode
+                             nil
+                             (cond ((eq compilation-highlight-regexp t))
+                                   (compilation-highlight-regexp
+                                    (if (eq program "fgrep")
+                                        (regexp-quote regex)
+                                      regex)))))
+      (compile-internal command (format "No more %s matches" program)
+                        "Igrep" nil grep-regexp-alist))))
+
+;; Analogue commands:
+
+(defmacro igrep-define (analogue-command &rest igrep-bindings)
+  "Define ANALOGUE-COMMAND as an `igrep' analogue command.
+Optional (VARIABLE VALUE) arguments specify the temporary IGREP-BINDINGS
+for the command."
+  ;; (interactive "SCommand: ") ; C-u => read bindings?
+  (let ((analogue-program (symbol-name analogue-command)))
+    `(defun ,analogue-command (&rest igrep-args)
+       ,(format "*Run `%s` via `\\[igrep]'.
+All arguments (including prefix arguments, when called interactively)
+are handled by `igrep'."
+		analogue-program)
+       (interactive
+	(let ((igrep-program (if igrep-program ,analogue-program))
+	      (igrep-program-default ,analogue-program))
+	  (igrep-read-args)))
+       (let (,@ igrep-bindings)
+	 (apply 'igrep
+		(cond ((interactive-p) (car igrep-args))
+		      ((car igrep-args))
+		      (t ,analogue-program))
+		(cdr igrep-args))))))
+
+(igrep-define egrep)
+(igrep-define fgrep)
+(igrep-define agrep
+  (igrep-use-zgrep nil)
+  (igrep-regex-option "-e"))
+
+;; Recursive (`find`) commands:
+
+;;;###autoload
+(defun igrep-find (&rest igrep-args)
+  "*Run `grep` via `find`; see `igrep' and `igrep-find'.
+All IGREP-ARGS (including prefix arguments, when called interactively)
+are handled by `igrep'."
+  (interactive
+   (let ((igrep-find t))
+     (igrep-read-args)))
+  (let ((igrep-find t))
+    (apply 'igrep igrep-args)))
+
+;; Analogue recursive (`find`) commands:
+
+(defmacro igrep-find-define (analogue-command &rest igrep-bindings)
+  "Define ANALOGUE-COMMAND-find as an `igrep' analogue `find` command.
+Optional (VARIABLE VALUE) arguments specify the temporary IGREP-BINDINGS
+for the command."
+  ;; (interactive "SCommand: ") ; C-u => read bindings?
+  (let ((analogue-program (symbol-name analogue-command)))
+    (setq analogue-command
+	  (intern (format "%s-find" analogue-command)))
+    `(defun ,analogue-command (&rest igrep-args)
+       ,(format "*Run `%s` via `\\[igrep-find]'.
+All arguments (including prefix arguments, when called interactively)
+are handled by `igrep'."
+		analogue-program)
+       (interactive
+	(let ((igrep-program (if igrep-program ,analogue-program))
+	      (igrep-program-default ,analogue-program)
+	      (igrep-find t))
+	  (igrep-read-args)))
+       (let (,@ igrep-bindings)
+	 (apply 'igrep-find
+		(cond ((interactive-p) (car igrep-args))
+		      ((car igrep-args))
+		      (t ,analogue-program))
+		(cdr igrep-args))))))
+
+(igrep-find-define egrep)
+(igrep-find-define fgrep)
+(igrep-find-define agrep
+  (igrep-use-zgrep nil)
+  (igrep-regex-option "-e"))
+
+;;;###autoload
+(defun igrep-visited-files (program regex &optional options)
+  "*Run `grep` PROGRAM to match REGEX (with optional OPTIONS) \
+on all visited files.
+See `\\[igrep]'."
+  (interactive
+   (let ((igrep-args (igrep-read-args 'no-files)))
+     ;; Delete FILES:
+     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
+     igrep-args))
+  (igrep program regex
+	 (let ((directory-abbrev-alist
+		(cons (cons (regexp-quote (expand-file-name default-directory))
+			    "./")	; or even ""
+		      directory-abbrev-alist)))
+	   (mapcar 'abbreviate-file-name
+		   (apply 'nconc
+			  (mapcar (lambda (buffer)
+				    (let ((file (buffer-file-name buffer)))
+				      (if (and file
+					       (cond ((featurep 'ange-ftp)
+						      (not (ange-ftp-ftp-name file)))
+						     ((featurep 'efs)
+						      (not (efs-ftp-path file)))
+						     (t t))
+					       ;; (file-exists-p file)
+					       )
+					  (list file))))
+				  (buffer-list)))))
+	 options))
+
+;; Dired commands:
+
+;;;###autoload
+(defun dired-do-igrep (program regex &optional options arg)
+  "*Search the marked (or next prefix ARG) files.
+See `\\[igrep]' for a description of PROGRAM, REGEX, and OPTIONS."
+  (interactive
+   (let ((igrep-args
+	  (let ((current-prefix-arg nil))
+	    (igrep-read-args 'no-files))))
+     ;; Delete FILES:
+     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
+     ;; Append ARG:
+     (nconc igrep-args (list current-prefix-arg))))
+  (igrep program regex
+	 (funcall (cond ((fboundp 'dired-get-marked-files) ; GNU Emacs
+			 'dired-get-marked-files)
+			((fboundp 'dired-mark-get-files) ; XEmacs
+			 'dired-mark-get-files))
+		  t arg)
+	 options))
+
+;; Dired recursive (`find`) commands:
+
+;;;###autoload
+(defun dired-do-igrep-find (program regex &optional options arg)
+  "*Run `grep` on the marked (or next prefix ARG) directories.
+See `\\[igrep]' for a description of PROGRAM, REGEX, and OPTIONS."
+  (interactive
+   (let ((igrep-args
+	  (let ((current-prefix-arg nil)
+		(igrep-find t))
+	    (igrep-read-args 'no-files))))
+     ;; Delete FILES:
+     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
+     ;; Append ARG:
+     (nconc igrep-args (list current-prefix-arg))))
+  (let ((igrep-find t))
+    (dired-do-igrep program regex options arg)))
+
+;; Buffer menu commands:
+
+;;;###autoload
+(defun Buffer-menu-igrep (program regex &optional options)
+  "*Run `grep` on the files visited in buffers marked with '>'.
+See `\\[igrep]' for a description of PROGRAM, REGEX, and OPTIONS."
+  (interactive
+   (let ((igrep-args (igrep-read-args 'no-files)))
+     ;; Delete FILES:
+     (setcdr (nthcdr 1 igrep-args) (nthcdr 3 igrep-args))
+     igrep-args))
+  ;; See Buffer-menu-select:
+  (let ((marked-files '())
+	marked-buffer
+	file)
+    (goto-char (point-min))
+    (while (search-forward "\n>" nil t)
+      (setq marked-buffer (Buffer-menu-buffer t)
+	    file (buffer-file-name marked-buffer))
+      (if (and file
+	       ;; local:
+	       (cond ((featurep 'ange-ftp)
+		      (not (ange-ftp-ftp-name file)))
+		     ((featurep 'efs)
+		      (not (efs-ftp-path file)))
+		     (t t)))
+	  (setq marked-files (cons file marked-files)))
+;;;    (let ((buffer-read-only nil))
+;;;      (delete-char -1)
+;;;      (insert ?\ ))
+      )
+    (setq marked-files (nreverse marked-files))
+    (igrep program regex
+	   (let ((directory-abbrev-alist
+		  (cons (cons (regexp-quote (expand-file-name default-directory))
+			      "./")	; or even ""
+			directory-abbrev-alist)))
+	     (mapcar 'abbreviate-file-name marked-files))
+	   options)))
+
+;; User functions:
+
+(defun igrep-dired-file-current-word ()
+  "Return the current word in the file on this line, if it is visible;
+else, return the file name on this line, if there is one;
+otherwise, return the current word."
+  (let* ((dired-file
+	  (dired-get-filename t t))
+	 (dired-file-buffer
+	  (if dired-file
+	      (get-file-buffer (expand-file-name dired-file))))
+	 (dired-file-buffer-window
+	  (if dired-file-buffer
+	      (get-buffer-window dired-file-buffer))))
+    (cond (dired-file-buffer-window (save-excursion
+				      (set-buffer dired-file-buffer)
+				      (current-word)))
+	  (dired-file)
+	  (t (current-word)))))
+
+(defun igrep-buffer-file-name-pattern ()
+  "Return a shell file name pattern based on the visited file name.
+If the `buffer-file-name' variable is nil, return \"*\"."
+  ;; (Based on other-possibly-interesting-files in ~/as-is/unix.el, by
+  ;; Wolfgang Rupprecht <wolfgang@mgm.mit.edu>.)
+  (if buffer-file-name
+      (let ((file-name (file-name-nondirectory buffer-file-name)))
+	(concat "*"
+		(save-match-data
+		  (if (string-match "\\.[^.]+\\(\\.g?[zZ]\\)?\\'"
+				    file-name)
+		      (substring file-name (match-beginning 0)
+				 (match-end 0))))))
+    "*"))
+
+(defun igrep-dired-directory-file-pattern ()
+  "Return a shell file name pattern based on `dired-directory', or \"*\"."
+  (cond ((stringp dired-directory)
+	 (if (file-directory-p dired-directory)
+	     "*"
+	   (file-name-nondirectory dired-directory))) ; wildcard
+	((consp dired-directory)	; (DIR FILE ...)
+	 (mapconcat 'identity (cdr dired-directory) " "))))
+
+;; Utilities:
+
+(defsubst igrep-file-directory (name)
+  "Return the directory component of NAME, or \".\" if it has none."
+  (directory-file-name (or (file-name-directory name)
+			   (file-name-as-directory "."))))
+
+(defsubst igrep-file-pattern (name)
+  "Return the file component of NAME, or \"*\" if it has none."
+  (let ((pattern (file-name-nondirectory name)))
+       (if (string= pattern "")
+	   "*"
+	 pattern)))
+
+(defun igrep-format-find-command (command files)
+  "Format `grep` COMMAND to be invoked via `find` on FILES."
+  (let ((directories '())
+	(patterns '()))
+    (while files
+      (let ((dir (igrep-file-directory (car files)))
+	    (pat (igrep-file-pattern (car files))))
+	(if (and (not (string= dir "."))
+		 (file-symlink-p dir))
+	    (setq dir (concat dir "/.")))
+	(if (not (member dir directories))
+	    (setq directories (cons dir directories)))
+	(cond ((equal pat "*")
+	       (setq patterns t))
+	      ((and (listp patterns)
+		    (not (member pat patterns)))
+	       (setq patterns (cons pat patterns)))))
+      (setq files (cdr files)))
+    (format (cond ((eq igrep-find-use-xargs 'gnu)
+		   ;; | \\\n
+		   "%s %s %s %s %s -print0 | xargs -0 -e %s")
+		  (igrep-find-use-xargs
+		   ;; | \\\n
+		   "%s %s %s %s %s -print | xargs -e %s")
+		  (t
+		   "%s %s %s %s %s -exec %s %s"))
+	    igrep-find-program
+	    (mapconcat 'igrep-quote-file-name (nreverse directories)
+		       " ")
+	    (if igrep-find-prune-clause
+		(format "%s -prune -o" igrep-find-prune-clause)
+	      "")
+	    (or igrep-find-file-clause "")
+	    (if (listp patterns)
+		(if (cdr patterns)	; (> (length patterns) 1)
+		    (format "%s %s %s"
+			    (shell-quote-argument "(")
+			    (mapconcat (lambda (pat)
+					 (format "-name %s"
+						 (shell-quote-argument pat)))
+				       (nreverse patterns)
+				       " -o ")
+			    (shell-quote-argument ")"))
+		  (format "-name %s" (shell-quote-argument (car patterns))))
+	      "")
+	    command
+	    (shell-quote-argument ";")
+	    )))
+
+(defmacro igrep-default-arg (variable)
+  "Return the default arg based on VARIABLE."
+  `(if ,variable
+       (cond ((get (quote ,variable) major-mode)
+	      (funcall (get (quote ,variable) major-mode)))
+	     (t (funcall ,variable)))))
+
+(defun igrep-default-regex ()
+  "Return the default REGEX for `\\[igrep]'."
+  (let ((default-regex (igrep-default-arg igrep-regex-default)))
+    (if (not (equal default-regex ""))
+	default-regex)))
+
+(defun igrep-default-files ()
+  "Return the default FILES for `\\[igrep]'."
+  (let* ((dired-subdirectory (if (cond ((fboundp 'derived-mode-p) ; Emacs 21
+					(derived-mode-p 'dired-mode))
+				       (t (eq major-mode 'dired-mode)))
+				 (dired-current-directory t)))
+	 (default-files (igrep-default-arg igrep-files-default)))
+    (if (not (listp default-files))	; stringp
+	(setq default-files (list default-files)))
+    (if dired-subdirectory
+	(mapcar (lambda (file)
+		  (concat dired-subdirectory file))
+		default-files)
+      default-files)))
+
+(defsubst igrep-prefix (prefix string &rest strings)
+  "Concatenate PREFIX (if non-nil), STRING, and any other STRINGS."
+  (if (or prefix strings)
+      (apply 'concat prefix string strings)
+    string))
+
+(defun igrep-read-args (&optional no-files)
+  "Read and return a list: (PROGRAM REGEX FILES OPTIONS).
+If NO-FILES is non-nil, then FILES is not read and nil is returned
+in its place."
+  (let* ((pre-prefix (if (and igrep-find (eq igrep-verbose-prompts t))
+			 "[find] "))
+	 (program
+	  (igrep-read-program pre-prefix))
+	 (prefix (if (and program (eq igrep-verbose-prompts t))
+		     (igrep-prefix pre-prefix program " ")
+		   pre-prefix))
+	 (options
+	  (igrep-read-options prefix))
+	 (post-prefix (if (and options (eq igrep-verbose-prompts t))
+			    (igrep-prefix prefix options " ")
+			  prefix)))
+    (list program
+	  (igrep-read-regex post-prefix)
+	  (if (not no-files)
+	      (igrep-read-files post-prefix))
+	  options)))
+
+(defun igrep-read-program (&optional prompt-prefix)
+  "Read and return a `grep` program name from the minibuffer.
+If `igrep-program' is non-nil, it.
+
+Optional PROMPT-PREFIX is prepended to the \"Program: \" prompt."
+  (or igrep-program
+      (let ((prompt "Program: "))
+	(completing-read (igrep-prefix prompt-prefix prompt) igrep-program-table
+			 nil t igrep-program-default))))
+
+(defun igrep-read-options (&optional prompt-prefix)
+  "Read and return an options string from the minibuffer.
+If `current-prefix-arg' is '(4) or '(64), return `igrep-options'.
+
+Optional PROMPT-PREFIX is prepended to the \"Options: \" prompt."
+  (if (or igrep-read-options
+	  (and (consp current-prefix-arg)
+	       (memq (prefix-numeric-value current-prefix-arg)
+		     '(4 64))))
+      (let ((prompt "Options: "))
+	(read-string (igrep-prefix prompt-prefix prompt)
+		     (or igrep-options "-")))
+    igrep-options))
+
+(defun igrep-read-regex (&optional prompt-prefix)
+  "Read and return a `grep` regex(5) string from the minibuffer.
+Optional PROMPT-PREFIX is prepended to the \"Regex: \" prompt."
+  (if igrep-insert-default-key
+      (define-key minibuffer-local-map igrep-insert-default-key
+	'igrep-insert-default-regex))
+  (let* ((default-regex (igrep-default-regex))
+	 (prompt (igrep-prefix prompt-prefix
+			       (if default-regex
+				   (format "Regex [default: %s]: "
+					   default-regex)
+				 "Regex: ")))
+	 (regex (cond ((featurep 'xemacs) ; incompatible
+                       ;; DEFAULT-VALUE is the 7th arg in 21.4 (but 21.1
+                       ;; only accepts 6 args):
+		       (read-from-minibuffer prompt
+					     nil nil nil
+					     'igrep-regex-history
+					     nil)) ; ABBREV-TABLE
+		      ((>= emacs-major-version 20)
+		       (read-from-minibuffer prompt
+					     nil nil nil
+					     'igrep-regex-history
+					     default-regex))
+		      (t
+		       (read-from-minibuffer prompt
+					     nil nil nil
+					     'igrep-regex-history)))))
+    (if (equal regex "")
+	(progn
+	  (or (equal default-regex (car igrep-regex-history))
+	      (setq igrep-regex-history
+		    (cons default-regex igrep-regex-history)))
+	  default-regex)
+      regex)))
+
+(defun igrep-insert-default-regex (&optional clear-minibuffer)
+  "*Insert the default regex in the minibuffer.
+If a prefix argument is specified, CLEAR-MINIBUFFER contents first."
+  (interactive "P")
+  (if clear-minibuffer
+      (delete-region (if (fboundp 'minibuffer-prompt-end) ; Emacs 21
+			 (minibuffer-prompt-end)
+		       (point-min))
+		     (point-max)))
+  (insert (or (save-excursion
+		(set-buffer (window-buffer minibuffer-scroll-window))
+		(igrep-default-regex))
+	      "")))
+
+(defun igrep-insert-default-files (&optional clear-minibuffer)
+  "*Insert the default files in the minibuffer.
+If a prefix argument is specified, CLEAR-MINIBUFFER contents first."
+  (interactive "P")
+  (if clear-minibuffer
+      (delete-region (if (fboundp 'minibuffer-prompt-end) ; Emacs 21
+			 (minibuffer-prompt-end)
+		       (point-min))
+		     (point-max)))
+  (insert (mapconcat 'identity
+		     (save-excursion
+		       (set-buffer (window-buffer minibuffer-scroll-window))
+		       (igrep-default-files))
+		     " ")))
+
+(defsubst igrep-default-key (command &optional keymap key)
+  "Return the key bound to COMMAND in KEYMAP, preferably KEY."
+  (if (null keymap)
+      (setq keymap (current-global-map)))
+  (if (and key
+	   (eq (lookup-key keymap key) command))
+      key
+    (where-is-internal command keymap t)))
+
+(defun igrep-read-files (&optional prompt-prefix)
+  "Read and return a file name pattern from the minibuffer.
+If `current-prefix-arg' is '(16) or '(64), read multiple file name
+patterns and return them in a list.  Optional PROMPT-PREFIX is
+prepended to the \"File(s): \" prompt."
+  (let* ((default-files (igrep-default-files))
+	 (default-files-string (mapconcat 'identity default-files " "))
+	 (insert-default-directory igrep-insert-default-directory)
+	 (file (igrep-read-file-name
+		(igrep-prefix prompt-prefix
+			      (if default-files
+				  (format "File(s) [default: %s]: "
+					  default-files-string)
+				"File(s): "))
+		nil (if default-files default-files-string "") nil nil
+		'igrep-files-history))
+	 (files (list file)))
+    (if (or igrep-read-multiple-files
+	    (and (consp current-prefix-arg)
+		 (memq (prefix-numeric-value current-prefix-arg)
+		       '(16 64))))
+	(let* ((key (igrep-default-key 'exit-minibuffer
+				       minibuffer-local-completion-map
+				       "\r"))
+	       (prompt
+		(igrep-prefix prompt-prefix
+			      (if igrep-verbose-prompts
+				  (format "File(s): [Type `%s' when done] "
+					  (key-description key))
+				"File(s): "))))
+	  (while (and (setq file
+			    (igrep-read-file-name prompt
+						  nil "" nil nil
+						  'igrep-files-history))
+		      (not (equal file "")))
+	    (setq files (cons file files)))))
+    (mapcar (lambda (file)
+	      (if (file-directory-p file)
+		  ;; really should map expand-file-name over default-files:
+		  (expand-file-name (if default-files default-files-string "*")
+				    file)
+		file))
+	    (nreverse files))))
+
+(defun igrep-read-file-name (prompt
+  &optional directory default existing initial history)
+  "Just like `read-file-name,' but with optional HISTORY."
+  (if igrep-insert-default-key
+      (define-key minibuffer-local-completion-map igrep-insert-default-key
+	'igrep-insert-default-files))
+  (if history
+      (let ((file-name-history (symbol-value history)))
+	(prog1 (read-file-name prompt directory default existing initial)
+	  (set history file-name-history)))
+    (read-file-name prompt directory default existing initial)))
+
+;; Menu bar:
+
+(if igrep-easy-menu
+    (progn
+      (easy-menu-define igrep-menu nil
+	"Menu keymap for igrep."
+	igrep-easy-menu)
+      (cond ((fboundp 'add-submenu)	; XEmacs
+	     (add-submenu '("Tools") igrep-menu "Grep..."))
+	    ((fboundp 'easy-menu-add-item) ; Emacs 20
+	     (easy-menu-add-item menu-bar-tools-menu nil igrep-menu
+				 'grep))
+	    (t				; Emacs 19
+	     (define-key-after menu-bar-tools-menu [igrep]
+	       (cons (car igrep-easy-menu) igrep-menu)
+	       (and (lookup-key menu-bar-tools-menu [grep]) 'grep))))))
+
+;;; Local Variables:
+;;; eval: (put 'igrep-define 'lisp-indent-function 1)
+;;; eval: (put 'igrep-find-define 'lisp-indent-function 1)
+;;; eval: (put 'easy-menu-define 'lisp-indent-function 'defun)
+;;; End:
+
+(provide 'igrep)
+
+;;; igrep.el ends here