Install Perl 5.8.8
[msysgit.git] / mingw / bin / search.bat
blob963cb2692138415947d8fcc88f62e296491f87d2
1 @rem = '--*-Perl-*--\r
2 @echo off\r
3 if "%OS%" == "Windows_NT" goto WinNT\r
4 perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9\r
5 goto endofperl\r
6 :WinNT\r
7 perl -x -S %0 %*\r
8 if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl\r
9 if %errorlevel% == 9009 echo You do not have Perl in your PATH.\r
10 if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul\r
11 goto endofperl\r
12 @rem ';\r
13 #!/usr/local/bin/perl -w\r
14 #line 15\r
15 'di';\r
16 'ig00';\r
17 ##############################################################################\r
18 ##\r
19 ## search\r
20 ##\r
21 ## Jeffrey Friedl (jfriedl@omron.co.jp), Dec 1994.\r
22 ## Copyright 19.... ah hell, just take it.\r
23 ##\r
24 ## BLURB:\r
25 ## A combo of find and grep -- more or less do a 'grep' on a whole\r
26 ## directory tree. Fast, with lots of options. Much more powerful than\r
27 ## the simple "find ... | xargs grep ....". Has a full man page.\r
28 ## Powerfully customizable.\r
29 ##\r
30 ## This file is big, but mostly comments and man page.\r
31 ##\r
32 ## See man page for usage info.\r
33 ## Return value: 2=error, 1=nothing found, 0=something found.\r
34 ##\r
36 $version = "950918.5";\r
37 ##\r
38 ## "950918.5";\r
39 ##      Changed all 'sysread' to 'read' because Linux perl's don't seem\r
40 ##      to like sysread()\r
41 ##\r
42 ## "941227.4";\r
43 ##      Added -n, -u\r
44 ##\r
45 ## "941222.3"\r
46 ##      Added -nice (due to Lionel Cons <Lionel.Cons@cern.ch>)\r
47 ##      Removed any leading "./" from name.\r
48 ##      Added default flags for ~/.search, including TTY, -nice, -list, etc.\r
49 ##      Program name now has path removed when printed in diagnostics.\r
50 ##      Added simple tilde-expansion to -dir arg.\r
51 ##      Added -dskip, etc. Fixed -iregex bug.\r
52 ##      Changed -dir to be additive, adding -ddir.\r
53 ##      Now screen out devices, pipes, and sockets.\r
54 ##      More tidying and lots of expanding of the man page\r
55 ##\r
56 ##\r
57 ## "941217.2";\r
58 ##      initial release.\r
60 $stripped=0;\r
62 &init;\r
63 if (exists $ENV{'HOME'}) {\r
64     $rc_file = join('/', $ENV{'HOME'}, ".search");\r
65 }\r
66 else {\r
67     $rc_file = "";\r
68 }\r
70 &check_args;\r
72 ## Make sure we've got a regex.\r
73 ## Don't need one if -find or -showrc was specified.\r
74 $!=2, die "expecting regex arguments.\n"\r
75         if $FIND_ONLY == 0 && $showrc == 0 && @ARGV == 0;\r
77 &prepare_to_search($rc_file);\r
79 &import_program if !defined &dodir; ## BIG key to speed.\r
81 ## do search while there are directories to be done.\r
82 &dodir(shift(@todo)) while @todo;\r
84 &clear_message if $VERBOSE && $STDERR_IS_TTY;\r
85 exit($retval);\r
86 ###############################################################################\r
88 sub init\r
89 {\r
90   ## initialize variables that might be reset by command-line args\r
91   $DOREP=0;             ## set true by -dorep (redo multi-hardlink files)\r
92   $DOREP=1 if $^O eq 'MSWin32';\r
93   $DO_SORT=0;           ## set by -sort (sort files in a dir before checking)\r
94   $FIND_ONLY=0;         ## set by -find (don't search files)\r
95   $LIST_ONLY=0;         ## set true by -l (list filenames only)\r
96   $NEWER=0;             ## set by -newer, "-mtime -###"\r
97   $NICE=0;              ## set by -nice (print human-readable output)\r
98   $NOLINKS=0;           ## set true by -nolinks (don't follow symlinks)\r
99   $OLDER=0;             ## set by -older, "-mtime  ###"\r
100   $PREPEND_FILENAME=1;  ## set false by -h (don't prefix lines with filename)\r
101   $REPORT_LINENUM=0;    ## set true by -n (show line numbers)\r
102   $VERBOSE=0;           ## set to a value by -v, -vv, etc. (verbose messages)\r
103   $WHY=0;               ## set true by -why, -vvv+ (report why skipped)\r
104   $XDEV=0;              ## set true by -xdev (stay on one filesystem)\r
105   $all=0;               ## set true by -all (don't skip many kinds of files)\r
106   $iflag = '';          ## set to 'i' by -i (ignore case);\r
107   $norc=0;              ## set by -norc (don't load rc file)\r
108   $showrc=0;            ## set by -showrc (show what happens with rc file)\r
109   $underlineOK=0;       ## set true by -u (watch for underline stuff)\r
110   $words=0;             ## set true by -w (match whole-words only)\r
111   $DELAY=0;             ## inter-file delay (seconds)\r
112   $retval=1;            ## will set to 0 if we find anything.\r
114   ## various elements of stat() that we might access\r
115   $STAT_DEV   = 1;\r
116   $STAT_INODE = 2;\r
117   $STAT_MTIME = 9;\r
119   $VV_PRINT_COUNT = 50;  ## with -vv, print every VV_PRINT_COUNT files, or...\r
120   $VV_SIZE = 1024*1024;  ## ...every VV_SIZE bytes searched\r
121   $vv_print = $vv_size = 0; ## running totals.\r
123   ## set default options, in case the rc file wants them\r
124   $opt{'TTY'}= 1 if -t STDOUT;\r
125   \r
126   ## want to know this for debugging message stuff\r
127   $STDERR_IS_TTY = -t STDERR ? 1 : 0;\r
128   $STDERR_SCREWS_STDOUT = ($STDERR_IS_TTY && -t STDOUT) ? 1 : 0;\r
130   $0 =~ s,.*/,,;  ## clean up $0 for any diagnostics we'll be printing.\r
133 ##\r
134 ## Check arguments.\r
135 ##\r
136 sub check_args\r
138   while (@ARGV && $ARGV[0] =~ m/^-/)\r
139   {\r
140       $arg = shift(@ARGV);\r
142       if ($arg eq '-version' || ($VERBOSE && $arg eq '-help')) {\r
143           print qq/Jeffrey's file search, version "$version".\n/;\r
144           exit(0) unless $arg eq '-help';\r
145       }\r
146       if ($arg eq '-help') {\r
147           print <<INLINE_LITERAL_TEXT;\r
148 usage: $0 [options] [-e] [PerlRegex ....]\r
149 OPTIONS TELLING *WHERE* TO SEARCH:\r
150   -dir DIR       start search at the named directory (default is current dir).\r
151   -xdev          stay on starting file system.\r
152   -sort          sort the files in each directory before processing.\r
153   -nolinks       don't follow symbolic links.\r
154 OPTIONS TELLING WHICH FILES TO EVEN CONSIDER:\r
155   -mtime #       consider files modified > # days ago (-# for < # days old)\r
156   -newer FILE    consider files modified more recently than FILE (also -older)\r
157   -name GLOB     consider files whose name matches pattern (also -regex).\r
158   -skip GLOB     opposite of -name: identifies files to not consider.\r
159   -path GLOB     like -name, but for files whose whole path is described.\r
160   -dpath/-dregex/-dskip versions for selecting or pruning directories.\r
161   -all           don't skip any files marked to be skipped by the startup file.\r
162   -x<SPECIAL>    (see manual, and/or try -showrc).\r
163   -why           report why a file isn't checked (also implied by -vvvv).\r
164 OPTIONS TELLING WHAT TO DO WITH FILES THAT WILL BE CONSIDERED:\r
165   -f  | -find    just list files (PerlRegex ignored). Default is to grep them.\r
166   -ff | -ffind   Does a faster -find (implies -find -all -dorep)\r
167 OPTIONS CONTROLLING HOW THE SEARCH IS DONE (AND WHAT IS PRINTED):\r
168   -l | -list     only list files with matches, not the lines themselves.\r
169   -nice | -nnice print more "human readable" output.\r
170   -n             prefix each output line with its line number in the file.\r
171   -h             don't prefix output lines with file name.\r
172   -u             also look "inside" manpage-style underlined text\r
173   -i             do case-insensitive searching.\r
174   -w             match words only (as defined by perl's \\b).\r
175 OTHER OPTIONS:\r
176   -v, -vv, -vvv  various levels of message verbosity.\r
177   -e             end of options (in case a regex looks like an option).\r
178   -showrc        show what the rc file sets, then exit.\r
179   -norc          don't load the rc file.\r
180   -dorep         check files with multiple hard links multiple times.\r
181 INLINE_LITERAL_TEXT\r
182         print "Use -v -help for more verbose help.\n" unless $VERBOSE;\r
183         print "This script file is also a man page.\n" unless $stripped;\r
184         print <<INLINE_LITERAL_TEXT if $VERBOSE;\r
186 If -f (or -find) given, PerlRegex is optional and ignored.\r
187 Otherwise, will search for files with lines matching any of the given regexes.\r
189 Combining things like -name and -mtime implies boolean AND.\r
190 However, duplicating things (such as -name '*.c' -name '*.txt') implies OR.\r
192 -mtime may be given floating point (i.e. 1.5 is a day and a half).\r
193 -iskip/-idskip/-ipath/... etc are case-insensitive versions.\r
195 If any letter in -newer/-older is upper case, "or equal" is\r
196 inserted into the test.\r
198 You can always find the latest version on the World Wide Web in\r
199    http://www.wg.omron.co.jp/~jfriedl/perl/\r
200 INLINE_LITERAL_TEXT\r
201           exit(0);\r
202       }\r
203       $DOREP=1,             next if $arg eq '-dorep';   ## do repeats\r
204       $DO_SORT=1,           next if $arg eq '-sort';    ## sort files\r
205       $NOLINKS=1,           next if $arg eq '-nolinks'; ## no sym. links\r
206       $PREPEND_FILENAME=0,  next if $arg eq '-h';       ## no filename prefix\r
207       $REPORT_LINENUM=1,    next if $arg eq '-n';       ## show line numbers\r
208       $WHY=1,               next if $arg eq '-why';     ## tell why skipped\r
209       $XDEV=1,              next if $arg eq '-xdev';    ## don't leave F.S.\r
210       $all=1,$opt{'-all'}=1,next if $arg eq '-all';     ## don't skip *.Z, etc\r
211       $iflag='i',           next if $arg eq '-i';       ## ignore case\r
212       $norc=1,              next if $arg eq '-norc';    ## don't load rc file\r
213       $showrc=1,            next if $arg eq '-showrc';  ## show rc file\r
214       $underlineOK=1,       next if $arg eq '-u';       ## look throuh underln.\r
215       $words=1,             next if $arg eq '-w';       ## match "words" only\r
216       &strip                     if $arg eq '-strip';   ## dump this program\r
217       last                       if $arg eq '-e';\r
218       $DELAY=$1,            next if $arg =~ m/-delay(\d+)/;\r
220       $FIND_ONLY=1,         next if $arg =~/^-f(ind)?$/;## do "find" only\r
222       $FIND_ONLY=1, $DOREP=1, $all=1,\r
223                             next if $arg =~/^-ff(ind)?$/;## fast -find\r
224       $LIST_ONLY=1,$opt{'-list'}=1,\r
225                             next if $arg =~/^-l(ist)?$/;## only list files\r
227       if ($arg =~ m/^-(v+)$/) { ## verbosity\r
228         $VERBOSE =length($1);\r
229         foreach $len (1..$VERBOSE) { $opt{'-'.('v' x $len)}=1 }\r
230         next;\r
231       }\r
232       if ($arg =~ m/^-(n+)ice$/) { ## "nice" output\r
233         $NICE =length($1);\r
234         foreach $len (1..$NICE) { $opt{'-'.('n' x $len).'ice'}=1 }\r
235         next;\r
236       }\r
238       if ($arg =~ m/^-(i?)(d?)skip$/) {\r
239           local($i) = $1 eq 'i';\r
240           local($d) = $2 eq 'd';\r
241           $! = 2, die qq/$0: expecting glob arg to -$arg\n/ unless @ARGV;\r
242           foreach (split(/\s+/, shift @ARGV)) {\r
243               if ($d) {\r
244                   $idskip{$_}=1 if $i;\r
245                    $dskip{$_}=1;\r
246               } else {\r
247                   $iskip{$_}=1 if $i;\r
248                    $skip{$_}=1;\r
249               }\r
250           }\r
251           next;\r
252       }\r
255       if ($arg =~ m/^-(i?)(d?)(regex|path|name)$/) {\r
256           local($i) = $1 eq 'i';\r
257           $! = 2, die qq/$0: expecting arg to -$arg\n/ unless @ARGV;\r
258           foreach (split(/\s+/, shift @ARGV)) {\r
259               $iname{join(',', $arg, $_)}=1 if $i;\r
260                $name{join(',', $arg, $_)}=1;\r
261           }\r
262           next;\r
263       }\r
265       if ($arg =~ m/^-d?dir$/) {\r
266           $opt{'-dir'}=1;\r
267           $! = 2, die qq/$0: expecting filename arg to -$arg\n/ unless @ARGV;\r
268           $start = shift(@ARGV);\r
269           $start =~ s#^~(/+|$)#$ENV{'HOME'}$1# if defined $ENV{'HOME'};\r
270           $! = 2, die qq/$0: can't find ${arg}'s "$start"\n/ unless -e $start;\r
271           $! = 2, die qq/$0: ${arg}'s "$start" not a directory.\n/ unless -d _;\r
272           undef(@todo), $opt{'-ddir'}=1 if $arg eq '-ddir';\r
273           push(@todo, $start);\r
274           next;\r
275       }\r
277       if ($arg =~ m/^-(new|old)er$/i) {\r
278           $! = 2, die "$0: expecting filename arg to -$arg\n" unless @ARGV;\r
279           local($file, $time) = shift(@ARGV);\r
280           $! = 2, die qq/$0: can't stat -${arg}'s "$file"./\r
281                   unless $time = (stat($file))[$STAT_MTIME];\r
282           local($upper) = $arg =~ tr/A-Z//;\r
283           if ($arg =~ m/new/i) {\r
284              $time++ unless $upper;\r
285              $NEWER = $time if $NEWER < $time;\r
286           } else {\r
287              $time-- unless $upper;\r
288              $OLDER = $time if $OLDER == 0 || $OLDER > $time;\r
289           }\r
290           next;\r
291       }\r
293       if ($arg =~ m/-mtime/) {\r
294           $! = 2, die "$0: expecting numerical arg to -$arg\n" unless @ARGV;\r
295           local($days) = shift(@ARGV);\r
296           $! = 2, die qq/$0: inappropriate arg ($days) to $arg\n/ if $days==0;\r
297           $days *= 3600 * 24;\r
298           if ($days < 0) {\r
299               local($time) = $^T + $days;\r
300               $NEWER = $time if $NEWER < $time;\r
301           } else {\r
302               local($time) = $^T - $days;\r
303               $OLDER = $time if $OLDER == 0 || $OLDER > $time;\r
304           }\r
305           next;\r
306       }\r
308       ## special user options\r
309       if ($arg =~ m/^-x(.+)/) {\r
310           foreach (split(/[\s,]+/, $1)) {  $user_opt{$_} = $opt{$_}= 1;  }\r
311           next;\r
312       }\r
314       $! = 2, die "$0: unknown arg [$arg]\n";\r
315   }\r
318 ##\r
319 ## Given a filename glob, return a regex.\r
320 ## If the glob has no globbing chars (no * ? or [..]), then\r
321 ## prepend an effective '*' to it.\r
322 ##\r
323 sub glob_to_regex\r
325     local($glob) = @_;\r
326     local(@parts) = $glob =~ m/\\.|[*?]|\[]?[^]]*]|[^[\\*?]+/g;\r
327     local($trueglob)=0;\r
328     foreach (@parts) {\r
329         if ($_ eq '*' || $_ eq '?') {\r
330             $_ = ".$_";\r
331             $trueglob=1;  ## * and ? are a real glob\r
332         } elsif (substr($_, 0, 1) eq '[') {\r
333             $trueglob=1;  ## [..] is a real glob\r
334         } else {\r
335             s/^\\//;     ## remove any leading backslash;\r
336             s/\W/\\$&/g; ## now quote anything dangerous;\r
337         }\r
338     }\r
339     unshift(@parts, '.*') unless $trueglob;\r
340     join('', '^', @parts, '$');\r
343 sub prepare_to_search\r
345   local($rc_file) = @_;\r
347   $HEADER_BYTES=0;          ## Might be set nonzero in &read_rc;\r
348   $last_message_length = 0; ## For &message and &clear_message.\r
350   &read_rc($rc_file, $showrc) unless $norc;\r
351   exit(0) if $showrc;\r
353   $NEXT_DIR_ENTRY = $DO_SORT ? 'shift @files' : 'readdir(DIR)';\r
354   $WHY = 1 if $VERBOSE > 3; ## Arg -vvvv or above implies  -why.\r
355   @todo = ('.') if @todo == 0; ## Where we'll start looking\r
357   ## see if any user options were specified that weren't accounted for\r
358   foreach $opt (keys %user_opt) {\r
359       next if defined $seen_opt{$opt};\r
360       warn "warning: -x$opt never considered.\n";\r
361   }\r
363   die "$0: multiple time constraints exclude all possible files.\n"\r
364       if ($NEWER && $OLDER) && ($NEWER > $OLDER);\r
366   ##\r
367   ## Process any -skip/-iskip args that had been given\r
368   ##\r
369   local(@skip_test);\r
370   foreach $glob (keys %skip) {\r
371       $i = defined($iskip{$glob}) ? 'i': '';\r
372       push(@skip_test, '$name =~ m/'. &glob_to_regex($glob). "/$i");\r
373   }\r
374   if (@skip_test) {\r
375       $SKIP_TEST = join('||',@skip_test);\r
376       $DO_SKIP_TEST = 1;\r
377   } else {\r
378       $DO_SKIP_TEST = $SKIP_TEST = 0;\r
379   }\r
381   ##\r
382   ## Process any -dskip/-idskip args that had been given\r
383   ##\r
384   local(@dskip_test);\r
385   foreach $glob (keys %dskip) {\r
386       $i = defined($idskip{$glob}) ? 'i': '';\r
387       push(@dskip_test, '$name =~ m/'. &glob_to_regex($glob). "/$i");\r
388   }\r
389   if (@dskip_test) {\r
390       $DSKIP_TEST = join('||',@dskip_test);\r
391       $DO_DSKIP_TEST = 1;\r
392   } else {\r
393       $DO_DSKIP_TEST = $DSKIP_TEST = 0;\r
394   }\r
397   ##\r
398   ## Process any -name, -path, -regex, etc. args that had been given.\r
399   ##\r
400   undef @name_test;\r
401   undef @dname_test;\r
402   foreach $key (keys %name) {\r
403       local($type, $pat) = split(/,/, $key, 2);\r
404       local($i) = defined($iname{$key}) ? 'i' : '';\r
405       if ($type =~ /regex/) {\r
406           $pat =~ s/!/\\!/g;\r
407           $test = "\$name =~ m!^$pat\$!$i";\r
408       } else {\r
409           local($var) = $type eq 'name' ? '$name' : '$file';\r
410           $test = "$var =~ m/". &glob_to_regex($pat). "/$i";\r
411       }\r
412       if ($type =~ m/^-i?d/) {\r
413           push(@dname_test, $test);\r
414       } else {\r
415           push(@name_test, $test);\r
416       }\r
417   }\r
418   if (@name_test) {\r
419       $GLOB_TESTS = join('||', @name_test);\r
421       $DO_GLOB_TESTS = 1;\r
422   } else {\r
423       $GLOB_TESTS = $DO_GLOB_TESTS = 0;\r
424   }\r
425   if (@dname_test) {\r
426       $DGLOB_TESTS = join('||', @dname_test);\r
427       $DO_DGLOB_TESTS = 1;\r
428   } else {\r
429       $DGLOB_TESTS = $DO_DGLOB_TESTS = 0;\r
430   }\r
433   ##\r
434   ## Process any 'magic' things from the startup file.\r
435   ##\r
436   if (@magic_tests && $HEADER_BYTES) {\r
437       ## the $magic' one is for when &dodir is not inlined\r
438       $tests = join('||',@magic_tests);\r
439       $MAGIC_TESTS = " { package magic; \$val = ($tests) }";\r
440       $DO_MAGIC_TESTS = 1;\r
441   } else {\r
442       $MAGIC_TESTS = 1;\r
443       $DO_MAGIC_TESTS = 0;\r
444   }\r
446   ##\r
447   ## Prepare regular expressions.\r
448   ##\r
449   {\r
450       local(@regex_tests);\r
452       if ($LIST_ONLY) {\r
453          $mflag = '';\r
454          ## need to have $* set, but perl5 just won''t shut up about it.\r
455          if ($] >= 5) {\r
456               $mflag = 'm';\r
457          } else {\r
458               eval ' $* = 1 ';\r
459          }\r
460       }\r
462       ##\r
463       ## Until I figure out a better way to deal with it,\r
464       ## We have to worry about a regex like [^xyz] when doing $LIST_ONLY.\r
465       ## Such a regex *will* match \n, and if I'm pulling in multiple\r
466       ## lines, it can allow lines to match that would otherwise not match.\r
467       ##\r
468       ## Therefore, if there is a '[^' in a regex, we can NOT take a chance\r
469       ## an use the fast listonly.\r
470       ##\r
471       $CAN_USE_FAST_LISTONLY = $LIST_ONLY;\r
473       local(@extra);\r
474       local($underline_glue) = ($] >= 5) ? '(:?_\cH)?' : '(_\cH)?';\r
475       while (@ARGV) {\r
476           $regex = shift(@ARGV);\r
477           ##\r
478           ## If watching for underlined things too, add another regex.\r
479           ##\r
480           if ($underlineOK) {\r
481              if ($regex =~ m/[?*+{}()\\.|^\$[]/) {\r
482                 warn "$0: warning, can't underline-safe ``$regex''.\n";\r
483              } else {\r
484                 $regex = join($underline_glue, split(//, $regex));\r
485              }\r
486           }\r
488           ## If nothing special in the regex, just use index...\r
489           ## is quite a bit faster.\r
490           if (($iflag eq '') && ($words == 0) &&\r
491                         $regex !~ m/[?*+{}()\\.|^\$[]/)\r
492           {\r
493               push(@regex_tests, "(index(\$_, q+$regex+)>=0)");\r
495           } else {\r
496               $regex =~ s#[\$\@\/]\w#\\$&#;\r
497               if ($words) {\r
498                   if ($regex =~ m/\|/) {\r
499                       ## could be dangerous -- see if we can wrap in parens.\r
500                       if ($regex =~ m/\\\d/) {\r
501                           warn "warning: -w and a | in a regex is dangerous.\n"\r
502                       } else {\r
503                           $regex = join($regex, '(', ')');\r
504                       }\r
505                   }\r
506                   $regex = join($regex, '\b', '\b');\r
507               }\r
508               $CAN_USE_FAST_LISTONLY = 0 if substr($regex, "[^") >= 0;\r
509               push(@regex_tests, "m/$regex/$iflag$mflag");\r
510           }\r
512           ## If we're done, but still have @extra to do, get set for that.\r
513           if (@ARGV == 0 && @extra) {\r
514               @ARGV = @extra;   ## now deal with the extra stuff.\r
515               $underlineOK = 0; ## but no more of this.\r
516               undef @extra;     ## or this.\r
517           }\r
518       }\r
519       if (@regex_tests) {\r
520           $REGEX_TEST = join('||', @regex_tests);\r
521           ## print STDERR $REGEX_TEST, "\n"; exit;\r
522       } else {\r
523           ## must be doing -find -- just give something syntactically correct.\r
524           $REGEX_TEST = 1;\r
525       }\r
526   }\r
528   ##\r
529   ## Make sure we can read the first item(s).\r
530   ##\r
531   foreach $start (@todo) {\r
532       $! = 2, die qq/$0: can't stat "$start"\n/\r
533           unless ($dev,$inode) = (stat($start))[$STAT_DEV,$STAT_INODE];\r
535       if (defined $dir_done{"$dev,$inode"}) {\r
536           ## ignore the repeat.\r
537           warn(qq/ignoring "$start" (same as "$dir_done{"$dev,$inode"}").\n/)\r
538                 if $VERBOSE;\r
539           next;\r
540       }\r
542       ## if -xdev was given, remember the device.\r
543       $xdev{$dev} = 1 if $XDEV;\r
545       ## Note that we won't want to do it again\r
546       $dir_done{"$dev,$inode"} = $start;\r
547   }\r
551 ##\r
552 ## See the comment above the __END__ above the 'sub dodir' below.\r
553 ##\r
554 sub import_program\r
556     sub bad {\r
557         print STDERR "$0: internal error (@_)\n";\r
558         exit 2;\r
559     }\r
561     ## Read from data, up to next __END__. This will be &dodir.\r
562     local($/) = "\n__END__";\r
563     $prog = <DATA>;\r
564     close(DATA);\r
566     $prog =~ s/\beval\b//g;       ## remove any 'eval'\r
568     ## Inline uppercase $-variables by their current values.\r
569     if ($] >= 5) {\r
570         $prog =~ s/\$([A-Z][A-Z0-9_]{2,}\b)/\r
571                     &bad($1) if !defined ${$main::{$1}}; ${$main::{$1}};/eg;\r
572     } else {\r
573         $prog =~ s/\$([A-Z][A-Z0-9_]{2,}\b)/local(*VAR) = $_main{$1};\r
574                     &bad($1) if !defined $VAR; $VAR;/eg;\r
575     }\r
577     eval $prog;  ## now do it. This will define &dodir;\r
578     $!=2, die "$0 internal error: $@\n" if $@;\r
581 ###########################################################################\r
583 ##\r
584 ## Read the .search file:\r
585 ##    Blank lines and lines that are only #-comments ignored.\r
586 ##    Newlines may be escaped to create long lines\r
587 ##    Other lines are directives.\r
588 ##\r
589 ##    A directive may begin with an optional tag in the form <...>\r
590 ##    Things inside the <...> are evaluated as with:\r
591 ##         <(this || that) && must>\r
592 ##    will be true if\r
593 ##       -xmust -xthis   or   -xmust -xthat\r
594 ##    were specified on the command line (order doesn't matter, though)\r
595 ##    A directive is not done if there is a tag and it's false.\r
596 ##    Any characters but whitespace and &|()>,! may appear after an -x\r
597 ##    (although "-xdev" is special).  -xmust,this is the same as -xmust -xthis.\r
598 ##    Something like -x~ would make <~> true, and <!~> false.\r
599 ##\r
600 ##    Directives are in the form:\r
601 ##      option: STRING\r
602 ##      magic : NUMBYTES : EXPR\r
603 ##\r
604 ##    With option:\r
605 ##      The STRING is parsed like a Bourne shell command line, and the\r
606 ##      options are used as if given on the command line.\r
607 ##      No comments are allowed on 'option' lines.\r
608 ##      Examples:\r
609 ##          # skip objects and libraries\r
610 ##          option: -skip '.o .a'\r
611 ##          # skip emacs *~ and *# files, unless -x~ given:\r
612 ##          <!~> option: -skip '~ #'\r
613 ##\r
614 ##    With magic:\r
615 ##      EXPR can be pretty much any perl (comments allowed!).\r
616 ##      If it evaluates to true for any particular file, it is skipped.\r
617 ##      The only info you'll have about a file is the variable $H, which\r
618 ##      will have at least the first NUMBYTES of the file (less if the file\r
619 ##      is shorter than that, of course, and maybe more). You'll also have\r
620 ##      any variables you set in previous 'magic' lines.\r
621 ##      Examples:\r
622 ##          magic: 6 : ($x6 = substr($H, 0, 6)) eq 'GIF87a'\r
623 ##          magic: 6 :  $x6                     eq 'GIF89a'\r
624 ##\r
625 ##          magic: 6 : (($x6 = substr($H, 0, 6)) eq 'GIF87a' ## old gif \\r
626 ##                                       || $x6  eq 'GIF89a' ## new gif\r
627 ##      (the above two sets are the same)\r
628 ##          ## Check the first 32 bytes for "binarish" looking bytes.\r
629 ##          ## Don't blindly dump on any high-bit set, as non-ASCII text\r
630 ##          ## often has them set. \x80 and \xff seem to be special, though.\r
631 ##          ## Require two in a row to not get things like perl's $^T.\r
632 ##          ## This is known to get *.Z, *.gz, pkzip, *.elc and about any\r
633 ##          ## executable you'll find.\r
634 ##          magic: 32 : $H =~ m/[\x00-\x06\x10-\x1a\x1c-\x1f\x80\xff]{2}/\r
635 ##\r
636 sub read_rc\r
638     local($file, $show) = @_;\r
639     local($line_num, $ln, $tag) = 0;\r
640     local($use_default, @default) = 0;\r
642     { package magic; $^W= 0; } ## turn off warnings for when we run EXPR's\r
644     unless (open(RC, "$file")) {\r
645         $use_default=1;\r
646         $file = "<internal default startup file>";\r
647         ## no RC file -- use this default.\r
648         @default = split(/\n/,<<'--------INLINE_LITERAL_TEXT');\r
649             magic: 32 : $H =~ m/[\x00-\x06\x10-\x1a\x1c-\x1f\x80\xff]{2}/\r
650             option: -skip '.a .elc .gz .o .pbm .xbm .dvi'\r
651             option: -iskip '.com .exe .lib .pdb .tarz .zip .z .lzh .jpg .jpeg .gif .uu'\r
652             <!~> option: -skip '~ #'\r
653 --------INLINE_LITERAL_TEXT\r
654     }\r
656     ##\r
657     ## Make an eval error pretty.\r
658     ##\r
659     sub clean_eval_error {\r
660         local($_) = @_;\r
661         s/ in file \(eval\) at line \d+,//g; ## perl4-style error\r
662         s/ at \(eval \d+\) line \d+,//g;     ## perl5-style error\r
663         $_ = $` if m/\n/;                    ## remove all but first line\r
664         "$_\n";\r
665     }\r
667     print "reading RC file: $file\n" if $show;\r
669     while (defined($_ = ($use_default ? shift(@default) : <RC>))) {\r
670         $ln = ++$line_num;                           ## note starting line num.\r
671         $_ .= <RC>, $line_num++ while s/\\\n?$/\n/;  ## allow continuations\r
672         next if /^\s*(#.*)?$/;          ## skip blank or comment-only lines.\r
673         $do = '';\r
674         \r
675         ## look for an initial <...> tag.\r
676         if (s/^\s*<([^>]*)>//) {\r
677             ## This simple s// will make the tag ready to eval.\r
678             ($tag = $msg = $1) =~\r
679                 s/[^\s&|(!)]+/\r
680                         $seen_opt{$&}=1;         ## note seen option\r
681                         "defined(\$opt{q>$&>})"  ## (q>> is safe quoting here)\r
682                 /eg;\r
683             \r
684             ## see if the tag is true or not, abort this line if not.\r
685             $dothis = (eval $tag);\r
686             $!=2, die "$file $ln <$msg>: $_".&clean_eval_error($@) if $@;\r
688             if ($show) {\r
689                 $msg =~ s/[^\s&|(!)]+/-x$&/;\r
690                 $msg =~ s/\s*!\s*/ no /g;\r
691                 $msg =~ s/\s*&&\s*/ and /g;\r
692                 $msg =~ s/\s*\|\|\s*/ or /g;\r
693                 $msg =~ s/^\s+//; $msg =~ s/\s+$//;\r
694                 $do = $dothis ? "(doing because $msg)" :\r
695                                 "(do if $msg)";\r
696             } elsif (!$dothis) {\r
697                 next;\r
698             }\r
699         }\r
701         if (m/^\s*option\s*:\s*/) {\r
702             next if $all && !$show; ## -all turns off these checks;\r
703             local($_) = $';\r
704             s/\n$//;\r
705             local($orig) = $_;\r
706             print " $do option: $_\n" if $show;\r
707             local($0) = "$0 ($file)"; ## for any error message.\r
708             local(@ARGV);\r
709             local($this);\r
710             ##\r
711             ## Parse $_ as a Bourne shell line -- fill @ARGV\r
712             ##\r
713             while (length) {\r
714                 if (s/^\s+//) {\r
715                     push(@ARGV, $this) if defined $this;\r
716                     undef $this;\r
717                     next;\r
718                 }\r
719                 $this = '' if !defined $this;\r
720                 $this .= $1 while s/^'([^']*)'// ||\r
721                                   s/^"([^"]*)"// ||\r
722                                   s/^([^'"\s\\]+)//||\r
723                                   s/^(\\[\D\d])//;\r
724                 die "$file $ln: error parsing $orig at $_\n" if m/^\S/;\r
725             }\r
726             push(@ARGV, $this) if defined $this;\r
727             &check_args;\r
728             die qq/$file $ln: unused arg "@ARGV".\n/ if @ARGV;\r
729             next;\r
730         }\r
732         if (m/^\s*magic\s*:\s*(\d+)\s*:\s*/) {\r
733             next if $all && !$show; ## -all turns off these checks;\r
734             local($bytes, $check) = ($1, $');\r
736             if ($show) {\r
737                 $check =~ s/\n?$/\n/;\r
738                 print " $do contents: $check";\r
739             }\r
740             ## Check to make sure the thing at least compiles.\r
741             eval  "package magic; (\$H = '1'x \$main'bytes) && (\n$check\n)\n";\r
742             $! = 2, die "$file $ln: ".&clean_eval_error($@) if $@;\r
744             $HEADER_BYTES = $bytes if $bytes > $HEADER_BYTES;\r
745             push(@magic_tests, "(\n$check\n)");\r
746             next;\r
747         }\r
748         $! = 2, die "$file $ln: unknown command\n";\r
749     }\r
750     close(RC);\r
753 sub message\r
755     if (!$STDERR_IS_TTY) {\r
756         print STDERR $_[0], "\n";\r
757     } else {\r
758         local($text) = @_;\r
759         $thislength = length($text);\r
760         if ($thislength >= $last_message_length) {\r
761             print STDERR $text, "\r";\r
762         } else {\r
763             print STDERR $text, ' 'x ($last_message_length-$thislength),"\r";\r
764         }       \r
765         $last_message_length = $thislength;\r
766     }\r
769 sub clear_message\r
771     print STDERR ' ' x $last_message_length, "\r" if $last_message_length;\r
772     $vv_print = $vv_size = $last_message_length = 0;\r
775 ##\r
776 ## Output a copy of this program with comments, extra whitespace, and\r
777 ## the trailing man page removed. On an ultra slow machine, such a copy\r
778 ## might load faster (but I can't tell any difference on my machine).\r
779 ##\r
780 sub strip {\r
781     seek(DATA, 0, 0) || die "$0: can't reset internal pointer.\n";\r
782     while(<DATA>) {\r
783       print, next if /INLINE_LITERAL_TEXT/.../INLINE_LITERAL_TEXT/;\r
784       ## must mention INLINE_LITERAL_TEXT on this line!\r
785       s/\#\#.*|^\s+|\s+$//; ## remove cruft\r
786       last if $_ eq '.00;';\r
787       next if ($_ eq '') || ($_ eq "'di'") || ($_ eq "'ig00'");\r
788       s/\$stripped=0;/\$stripped=1;/;\r
789       s/\s\s+/ /;  ## squish multiple whitespaces down to one.\r
790       print $_, "\n";\r
791     }\r
792     exit(0);\r
795 ##\r
796 ## Just to shut up -w. Never executed.\r
797 ##\r
798 sub dummy {\r
800     1 || &dummy || &dir_done || &bad || &message || $NEXT_DIR_ENTRY ||\r
801     $DELAY || $VV_SIZE || $VV_PRINT_COUNT || $STDERR_SCREWS_STDOUT ||\r
802     @files || @files || $magic'H || $magic'H || $xdev{''} || &clear_message;\r
806 ##\r
807 ## If the following __END__ is in place, what follows will be\r
808 ## inlined when the program first starts up. Any $ variable name\r
809 ## all in upper case, specifically, any string matching\r
810 ##      \$([A-Z][A-Z0-9_]{2,}\b\r
811 ## will have the true value for that variable inlined. Also, any 'eval' is\r
812 ## removed\r
813 ##\r
814 ## The idea is that when the whole thing is then eval'ed to define &dodir,\r
815 ## the perl optimizer will make all the decisions that are based upon\r
816 ## command-line options (such as $VERBOSE), since they'll be inlined as\r
817 ## constants\r
818 ##\r
819 ## Also, and here's the big win, the tests for matching the regex, and a\r
820 ## few others, are all inlined. Should be blinding speed here.\r
821 ##\r
822 ## See the read from <DATA> above for where all this takes place.\r
823 ## But all-in-all, you *want* the __END__ here. Comment it out only for\r
824 ## debugging....\r
825 ##\r
827 __END__\r
829 ##\r
830 ## Given a directory, check all "appropriate" files in it.\r
831 ## Shove any subdirectories into the global @todo, so they'll be done\r
832 ## later.\r
833 ##\r
834 ## Be careful about adding any upper-case variables, as they are subject\r
835 ## to being inlined. See comments above the __END__ above.\r
836 ##\r
837 sub dodir\r
839   local($dir) = @_;\r
840   $dir =~ s,/+$,,; ## remove any trailing slash.\r
841   unless (opendir(DIR, "$dir/.")) {\r
842       &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
843       warn qq($0: can't opendir "$dir/".\n);\r
844       return;\r
845   }\r
847   if ($VERBOSE) {\r
848       &message($dir);\r
849       $vv_print = $vv_size = 0;\r
850   }\r
852   @files = sort readdir(DIR) if $DO_SORT;\r
854   while (defined($name = eval $NEXT_DIR_ENTRY))\r
855   {\r
856     next if $name eq '.' || $name eq '..'; ## never follow these.\r
858     ## create full relative pathname.\r
859     $file = $dir eq '.' ? $name : "$dir/$name";\r
861     ## if link and skipping them, do so.\r
862     if ($NOLINKS && -l $file) {\r
863         warn qq/skip (symlink): $file\n/ if $WHY;\r
864         next;\r
865     }\r
867     ## skip things unless files or directories\r
868     unless (-f $file || -d _) {\r
869         if ($WHY) {\r
870             $why = (-S _ && "socket")       ||\r
871                    (-p _ && "pipe")         ||\r
872                    (-b _ && "block special")||\r
873                    (-c _ && "char special") || "somekinda special";\r
874             warn qq/skip ($why): $file\n/;\r
875         }\r
876         next;\r
877     }\r
879     ## skip things we can't read\r
880     unless (-r _) {\r
881         if ($WHY) {\r
882             $why = (-l $file) ? "follow" : "read";\r
883             warn qq/skip (can't $why): $file\n/;\r
884         }\r
885         next;\r
886     }\r
888     ## skip things that are empty\r
889     unless (-s _ || -d _) {\r
890         warn qq/skip (empty): $file\n/ if $WHY;\r
891         next;\r
892     }\r
894     ## Note file device & inode. If -xdev, skip if appropriate.\r
895     ($dev, $inode) = (stat(_))[$STAT_DEV, $STAT_INODE];\r
896     if ($XDEV && defined $xdev{$dev}) {\r
897         warn qq/skip (other device): $file\n/ if $WHY;\r
898         next;\r
899     }\r
900     $id = "$dev,$inode";\r
902     ## special work for a directory\r
903     if (-d _) {\r
904         ## Do checks for directory file endings.\r
905         if ($DO_DSKIP_TEST && (eval $DSKIP_TEST)) {\r
906             warn qq/skip (-dskip): $file\n/ if $WHY;\r
907             next;\r
908         }\r
909         ## do checks for -name/-regex/-path tests\r
910         if ($DO_DGLOB_TESTS && !(eval $DGLOB_TESTS)) {\r
911             warn qq/skip (dirname): $file\n/ if $WHY;\r
912             next;\r
913         }\r
915         ## _never_ redo a directory\r
916         if (defined $dir_done{$id} and $^O ne 'MSWin32') {\r
917             warn qq/skip (did as "$dir_done{$id}"): $file\n/ if $WHY;\r
918             next;\r
919         }\r
920         $dir_done{$id} = $file;     ## mark it done.\r
921         unshift(@todo, $file);      ## add to the list to do.\r
922         next;\r
923     }\r
924     if ($WHY == 0  && $VERBOSE > 1) {\r
925       if ($VERBOSE>2||$vv_print++>$VV_PRINT_COUNT||($vv_size+=-s _)>$VV_SIZE){\r
926           &message($file);\r
927           $vv_print = $vv_size = 0;\r
928       }\r
929     }\r
931     ## do time-related tests\r
932     if ($NEWER || $OLDER) {\r
933         $_ = (stat(_))[$STAT_MTIME];\r
934         if ($NEWER && $_ < $NEWER) {\r
935             warn qq/skip (too old): $file\n/ if $WHY;\r
936             next;\r
937         }\r
938         if ($OLDER && $_ > $OLDER) {\r
939             warn qq/skip (too new): $file\n/ if $WHY;\r
940             next;\r
941         }\r
942     }\r
944     ## do checks for file endings\r
945     if ($DO_SKIP_TEST && (eval $SKIP_TEST)) {\r
946         warn qq/skip (-skip): $file\n/ if $WHY;\r
947         next;\r
948     }\r
950     ## do checks for -name/-regex/-path tests\r
951     if ($DO_GLOB_TESTS && !(eval $GLOB_TESTS)) {\r
952         warn qq/skip (filename): $file\n/ if $WHY;\r
953         next;\r
954     }\r
957     ## If we're not repeating files,\r
958     ##  skip this one if we've done it, or note we're doing it.\r
959     unless ($DOREP) {\r
960         if (defined $file_done{$id}) {\r
961             warn qq/skip (did as "$file_done{$id}"): $file\n/ if $WHY;\r
962             next;\r
963         }\r
964         $file_done{$id} = $file;\r
965     }\r
967     if ($DO_MAGIC_TESTS) {\r
968         if (!open(FILE_IN, $file)) {\r
969             &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
970             warn qq/$0: can't open: $file\n/;\r
971             next;\r
972         }\r
973         unless (read(FILE_IN, $magic'H, $HEADER_BYTES)) {\r
974             &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
975             warn qq/$0: can't read from "$file"\n"/;\r
976             close(FILE_IN);\r
977             next;\r
978         }\r
980         eval $MAGIC_TESTS;\r
981         if ($magic'val) {\r
982             close(FILE_IN);\r
983             warn qq/skip (magic): $file\n/ if $WHY;\r
984             next;\r
985         }\r
986         seek(FILE_IN, 0, 0);  ## reset for later <FILE_IN>\r
987     }\r
989     if ($WHY != 0  && $VERBOSE > 1) {\r
990       if ($VERBOSE>2||$vv_print++>$VV_PRINT_COUNT||($vv_size+=-s _)>$VV_SIZE){\r
991           &message($file);\r
992           $vv_print = $vv_size = 0;\r
993       }\r
994     }\r
996     if ($DELAY) {\r
997         sleep($DELAY);\r
998     }\r
1000     if ($FIND_ONLY) {\r
1001         &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
1002         print $file, "\n";\r
1003         $retval=0; ## we've found something\r
1004         close(FILE_IN) if $DO_MAGIC_TESTS;\r
1005         next;\r
1006     } else {\r
1007         ## if we weren't doing magic tests, file won't be open yet...\r
1008         if (!$DO_MAGIC_TESTS && !open(FILE_IN, $file)) {\r
1009             &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
1010             warn qq/$0: can't open: $file\n/;\r
1011             next;\r
1012         }\r
1013         if ($LIST_ONLY && $CAN_USE_FAST_LISTONLY) {\r
1014             ##\r
1015             ## This is rather complex, but buys us a LOT when we're just\r
1016             ## listing files and not the individual internal lines.\r
1017             ##\r
1018             local($size) = 4096;  ## block-size in which to do reads\r
1019             local($nl);           ## will point to $_'s ending newline.\r
1020             local($read);         ## will be how many bytes read.\r
1021             local($_) = '';       ## Starts out empty\r
1022             local($hold);         ## (see below)\r
1024             while (($read = read(FILE_IN,$_,$size,length($_)))||length($_))\r
1025             {\r
1026                 undef @parts;\r
1027                 ## if read a full block, but no newline, need to read more.\r
1028                 while ($read == $size && ($nl = rindex($_, "\n")) < 0) {\r
1029                     push(@parts, $_);                    ## save that part\r
1030                     $read = read(FILE_IN, $_, $size); ## keep trying\r
1031                 }\r
1033                 ##\r
1034                 ## If we had to save parts, must now combine them together.\r
1035                 ## adjusting $nl to reflect the now-larger $_. This should\r
1036                 ## be a lot more efficient than using any kind of .= in the\r
1037                 ## loop above.\r
1038                 ##\r
1039                 if (@parts) {\r
1040                     local($lastlen) = length($_); #only need if $nl >= 0\r
1041                     $_ = join('', @parts, $_);\r
1042                     $nl = length($_) - ($lastlen - $nl) if $nl >= 0;\r
1043                 }\r
1045                 ##\r
1046                 ## If we're at the end of the file, then we can use $_ as\r
1047                 ## is.  Otherwise, we need to remove the final partial-line\r
1048                 ## and save it so that it'll be at the beginning of the\r
1049                 ## next read (where the rest of the line will be layed in\r
1050                 ## right after it).  $hold will be what we should save\r
1051                 ## until next time.\r
1052                 ##\r
1053                 if ($read != $size || $nl < 0) {\r
1054                     $hold = '';\r
1055                 } else {\r
1056                     $hold = substr($_, $nl + 1);\r
1057                     substr($_, $nl + 1) = '';\r
1058                 }\r
1060                 ##\r
1061                 ## Now have a bunch of full lines in $_. Use it.\r
1062                 ##\r
1063                 if (eval $REGEX_TEST) {\r
1064                     &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
1065                     print $file, "\n";\r
1066                     $retval=0; ## we've found something\r
1068                     last;\r
1069                 }\r
1071                 ## Prepare for next read....\r
1072                 $_ = $hold;\r
1073             }\r
1075         } else {  ## else not using faster block scanning.....\r
1077             $lines_printed = 0 if $NICE;\r
1078             while (<FILE_IN>) {\r
1079                 study;\r
1080                 next unless (eval $REGEX_TEST);\r
1082                 ##\r
1083                 ## We found a matching line.\r
1084                 ##\r
1085                 $retval=0;\r
1086                 &clear_message if $VERBOSE && $STDERR_SCREWS_STDOUT;\r
1087                 if ($LIST_ONLY) {\r
1088                     print $file, "\n";\r
1089                     last;\r
1090                 } else {\r
1091                     ## prepare to print line.\r
1092                     if ($NICE && $lines_printed++ == 0) {\r
1093                         print '-' x 70, "\n" if $NICE > 1;\r
1094                         print $file, ":\n";\r
1095                     }\r
1097                     ##\r
1098                     ## Print all the prelim stuff. This looks less efficient\r
1099                     ## than it needs to be, but that's so that when the eval\r
1100                     ## is compiled (and the tests are optimized away), the\r
1101                     ## result will be less actual PRINTs than the more natural\r
1102                     ## way of doing these tests....\r
1103                     ##\r
1104                     if ($NICE) {\r
1105                         if ($REPORT_LINENUM) {\r
1106                             print " line $.:  ";\r
1107                         } else {\r
1108                             print "  ";\r
1109                         }\r
1110                     } elsif ($REPORT_LINENUM && $PREPEND_FILENAME) {\r
1111                         print "$file,:$.: ";\r
1112                     } elsif ($PREPEND_FILENAME) {\r
1113                         print "$file: ";\r
1114                     } elsif ($REPORT_LINENUM) {\r
1115                         print "$.: ";\r
1116                     }\r
1117                     print $_;\r
1118                     print "\n" unless m/\n$/;\r
1119                 }\r
1120             }\r
1121             print "\n" if ($NICE > 1) && $lines_printed;\r
1122         }\r
1123         close(FILE_IN);\r
1124     }\r
1125   }\r
1126   closedir(DIR);\r
1129 __END__\r
1130 .00;                    ## finish .ig\r
1131  \r
1132 'di                     \" finish diversion--previous line must be blank\r
1133 .nr nl 0-1              \" fake up transition to first page again\r
1134 .nr % 0                 \" start at page 1\r
1135 .\"__________________NORMAL_MAN_PAGE_BELOW_________________\r
1136 .ll+10n\r
1137 .TH search 1 "Dec 17, 1994"\r
1138 .SH SEARCH\r
1139 search \- search files (a'la grep) in a whole directory tree.\r
1140 .SH SYNOPSIS\r
1141 search [ grep-like and find-like options] [regex ....]\r
1142 .SH DESCRIPTION\r
1143 .I Search\r
1144 is more or less a combo of 'find' and 'grep' (although the regular\r
1145 expression flavor is that of the perl being used, which is closer to\r
1146 egrep's than grep's).\r
1148 .I Search\r
1149 does generally the same kind of thing that\r
1150 .nf\r
1151    find <blah blah> | xargs egrep <blah blah>\r
1152 .fi\r
1153 does, but is\r
1154 .I much\r
1155 more powerful and efficient (and intuitive, I think).\r
1157 This manual describes\r
1158 .I search\r
1159 as of version "941227.4". You can always find the latest version at\r
1160 .nf\r
1161    http://www.wg.omron.co.jp/~jfriedl/perl/index.html\r
1162 .fi\r
1164 .SH "QUICK EXAMPLE"\r
1165 Basic use is simple:\r
1166 .nf\r
1167     % search jeff\r
1168 .fi\r
1169 will search files in the current directory, and all sub directories, for\r
1170 files that have "jeff" in them. The lines will be listed with the\r
1171 containing file's name prepended.\r
1172 .PP\r
1173 If you list more than one regex, such as with\r
1174 .nf\r
1175     % search jeff Larry Randal+ 'Stoc?k' 'C.*son'\r
1176 .fi\r
1177 then a line containing any of the regexes will be listed.\r
1178 This makes it effectively the same as\r
1179 .nf\r
1180     % search 'jeff|Larry|Randal+|Stoc?k|C.*son'\r
1181 .fi\r
1182 However, listing them separately is much more efficient (and is easier\r
1183 to type).\r
1184 .PP\r
1185 Note that in the case of these examples, the\r
1186 .B \-w\r
1187 (list whole-words only) option would be useful.\r
1188 .PP\r
1189 Normally, various kinds of files are automatically removed from consideration.\r
1190 If it has has a certain ending (such as ".tar", ".Z", ".o", .etc), or if\r
1191 the beginning of the file looks like a binary, it'll be excluded.\r
1192 You can control exactly how this works -- see below. One quick way to\r
1193 override this is to use the\r
1194 .B \-all\r
1195 option, which means to consider all the files that would normally be\r
1196 automatically excluded.\r
1197 Or, if you're curious, you can use\r
1198 .B \-why\r
1199 to have notes about what files are skipped (and why) printed to stderr.\r
1201 .SH "BASIC OVERVIEW"\r
1202 Normally, the search starts in the current directory, considering files in\r
1203 all subdirectories.\r
1205 You can use the\r
1206 .I ~/.search\r
1207 file to control ways to automatically exclude files.\r
1208 If you don't have this file, a default one will kick in, which automatically\r
1209 add\r
1210 .nf\r
1211     -skip .o .Z .gif\r
1212 .fi\r
1213 (among others) to exclude those kinds of files (which you probably want to\r
1214 skip when searching for text, as is normal).\r
1215 Files that look to be be binary will also be excluded.\r
1217 Files ending with "#" and "~" will also be excluded unless the\r
1218 .B -x~\r
1219 option is given. \r
1221 You can use\r
1222 .B -showrc\r
1223 to show what kinds of files will normally be skipped.\r
1224 See the section on the startup file\r
1225 for more info.\r
1227 You can use the\r
1228 .B -all\r
1229 option to indicate you want to consider all files that would otherwise be\r
1230 skipped by the startup file.\r
1232 Based upon various other flags (see "WHICH FILES TO CONSIDER" below),\r
1233 more files might be removed from consideration. For example\r
1234 .nf\r
1235     -mtime 3\r
1236 .fi\r
1237 will exclude files that aren't at least three days old (change the 3 to -3\r
1238 to exclude files that are more than three days old), while\r
1239 .nf\r
1240     -skip .*\r
1241 .fi\r
1242 would exclude any file beginning with a dot (of course, '.' and '..'  are\r
1243 special and always excluded).\r
1245 If you'd like to see what files are being excluded, and why, you can get the\r
1246 list via the\r
1247 .B \-why\r
1248 option.\r
1250 If a file makes it past all the checks, it is then "considered".\r
1251 This usually means it is greped for the regular expressions you gave\r
1252 on the command line.\r
1254 If any of the regexes match a line, the line is printed.\r
1255 However, if\r
1256 .B -list\r
1257 is given, just the filename is printed. Or, if\r
1258 .B -nice\r
1259 is given, a somewhat more (human-)readable output is generated.\r
1261 If you're searching a huge tree and want to keep informed about how\r
1262 the search is progressing,\r
1263 .B -v\r
1264 will print (to stderr) the current directory being searched.\r
1265 Using\r
1266 .B -vv\r
1267 will also print the current file "every so often", which could be useful\r
1268 if a directory is huge. Using\r
1269 .B -vvv\r
1270 will print the update with every file.\r
1272 Below is the full listing of options.\r
1274 .SH "OPTIONS TELLING *WHERE* TO SEARCH"\r
1275 .TP\r
1276 .BI -dir " DIR"\r
1277 Start searching at the named directory instead of the current directory.\r
1278 If multiple\r
1279 .B -dir\r
1280 arguments are given, multiple trees will be searched.\r
1281 .TP\r
1282 .BI -ddir " DIR"\r
1283 Like\r
1284 .B -dir\r
1285 except it flushes any previous\r
1286 .B -dir\r
1287 directories (i.e. "-dir A -dir B -dir C" will search A, B, and C, while\r
1288 "-dir A -ddir B -dir C" will search only B and C. This might be of use\r
1289 in the startup file (see that section below).\r
1290 .TP\r
1291 .B -xdev\r
1292 Stay on the same filesystem as the starting directory/directories.\r
1293 .TP\r
1294 .B -sort\r
1295 Sort the items in a directory before processing them.\r
1296 Normally they are processed in whatever order they happen to be read from\r
1297 the directory.\r
1298 .TP\r
1299 .B -nolinks\r
1300 Don't follow symbolic links. Normally they're followed.\r
1302 .SH "OPTIONS CONTROLLING WHICH FILES TO CONSIDER AND EXCLUDE"\r
1303 .TP\r
1304 .BI -mtime " NUM"\r
1305 Only consider files that were last changed more than\r
1306 .I NUM\r
1307 days ago\r
1308 (less than\r
1309 .I NUM\r
1310 days if\r
1311 .I NUM\r
1312 has '-' prepended, i.e. "-mtime -2.5" means to consider files that\r
1313 have been changed in the last two and a half days).\r
1314 .TP\r
1315 .B -older FILE\r
1316 Only consider files that have not changed since\r
1317 .I FILE\r
1318 was last changed.\r
1319 If there is any upper case in the "-older", "or equal" is added to the sense\r
1320 of the test.  Therefore, "search -older ./file regex" will never consider\r
1321 "./file", while "search -Older ./file regex" will.\r
1323 If a file is a symbolic link, the time used is that of the file and not the\r
1324 link.\r
1325 .TP\r
1326 .BI -newer " FILE"\r
1327 Opposite of\r
1328 .BR -older .\r
1329 .TP\r
1330 .BI -name " GLOB"\r
1331 Only consider files that match the shell filename pattern\r
1332 .IR GLOB .\r
1333 The check is only done on a file's name (use\r
1334 .B -path\r
1335 to check the whole path, and use\r
1336 .B -dname\r
1337 to check directory names).\r
1339 Multiple specifications can be given by separating them with spaces, a'la\r
1340 .nf\r
1341     -name '*.c *.h'\r
1342 .fi\r
1343 to consider C source and header files.\r
1344 If\r
1345 .I GLOB\r
1346 doesn't contain any special pattern characters, a '*' is prepended.\r
1347 This last example could have been given as\r
1348 .nf\r
1349    -name '.c .h'\r
1350 .fi\r
1351 It could also be given as\r
1352 .nf\r
1353     -name .c -name .h\r
1354 .fi\r
1355 or\r
1356 .nf\r
1357     -name '*.c' -name '*.h'\r
1358 .fi\r
1359 or\r
1360 .nf\r
1361     -name '*.[ch]'\r
1362 .fi\r
1363 (among others)\r
1364 but in this last case, you have to be sure to supply the leading '*'.\r
1365 .TP\r
1366 .BI -path " GLOB"\r
1367 Like\r
1368 .B -name\r
1369 except the entire path is checked against the pattern.\r
1370 .TP\r
1371 .B -regex " REGEX"\r
1372 Considers files whose names (not paths) match the given perl regex\r
1373 exactly.\r
1374 .TP\r
1375 .BI -iname " GLOB"\r
1376 Case-insensitive version of\r
1377 .BR -name .\r
1378 .TP\r
1379 .BI -ipath " GLOB"\r
1380 Case-insensitive version of\r
1381 .BR -path .\r
1382 .TP\r
1383 .BI -iregex " REGEX"\r
1384 Case-insensitive version of\r
1385 .BR -regex .\r
1387 .TP\r
1388 .BI -dpath " GLOB"\r
1389 Only search down directories whose path matches the given pattern (this\r
1390 doesn't apply to the initial directory given by\r
1391 .BI -dir ,\r
1392 of course).\r
1393 Something like\r
1394 .nf\r
1395     -dir /usr/man -dpath /usr/man/man*\r
1396 .fi\r
1397 would completely skip\r
1398 "/usr/man/cat1", "/usr/man/cat2", etc.\r
1399 .TP\r
1400 .BI -dskip " GLOB"\r
1401 Skips directories whose name (not path) matches the given pattern.\r
1402 Something like\r
1403 .nf\r
1404     -dir /usr/man -dskip cat*\r
1405 .fi\r
1406 would completely skip any directory in the tree whose name begins with "cat"\r
1407 (including "/usr/man/cat1", "/usr/man/cat2", etc.).\r
1408 .TP\r
1409 .BI -dregex " REGEX"\r
1410 Like\r
1411 .BI -dpath ,\r
1412 but the pattern is a full perl regex. Note that this quite different\r
1413 from\r
1414 .B -regex\r
1415 which considers only file names (not paths). This option considers\r
1416 full directory paths (not just names). It's much more useful this way.\r
1417 Sorry if it's confusing.\r
1418 .TP\r
1419 .BI -dpath " GLOB"\r
1420 This option exists, but is probably not very useful. It probably wants to\r
1421 be like the '-below' or something I mention in the "TODO" section.\r
1422 .TP\r
1423 .BI -idpath " GLOB"\r
1424 Case-insensitive version of\r
1425 .BR -dpath .\r
1426 .TP\r
1427 .BI -idskip " GLOB"\r
1428 Case-insensitive version of\r
1429 .BR -dskip .\r
1430 .TP\r
1431 .BI -idregex " REGEX"\r
1432 Case-insensitive version of\r
1433 .BR -dregex .\r
1434 .TP\r
1435 .B -all\r
1436 Ignore any 'magic' or 'option' lines in the startup file.\r
1437 The effect is that all files that would otherwise be automatically\r
1438 excluded are considered.\r
1439 .TP\r
1440 .BI -x SPECIAL\r
1441 Arguments starting with\r
1442 .B -x\r
1443 (except\r
1444 .BR -xdev ,\r
1445 explained elsewhere) do special interaction with the\r
1446 .I ~/.search\r
1447 startup file. Something like\r
1448 .nf\r
1449         -xflag1 -xflag2\r
1450 .fi\r
1451 will turn on "flag1" and "flag2" in the startup file (and is\r
1452 the same as "-xflag1,flag2"). You can use this to write your own\r
1453 rules for what kinds of files are to be considered.\r
1455 For example, the internal-default startup file contains the line\r
1456 .nf\r
1457         <!~> option: -skip '~ #'\r
1458 .fi\r
1459 This means that if the\r
1460 .B -x~\r
1461 flag is\r
1462 .I not\r
1463 seen, the option\r
1464 .nf\r
1465     -skip '~ #'\r
1466 .fi\r
1467 should be done.\r
1468 The effect is that emacs temp and backup files are not normally\r
1469 considered, but you can included them with the -x~ flag.\r
1471 You can write your own rules to customize\r
1472 .I search\r
1473 in powerful ways. See the STARTUP FILE section below.\r
1474 .TP\r
1475 .B -why\r
1476 Print a message (to stderr) when and why a file is not considered.\r
1478 .SH "OPTIONS TELLING WHAT TO DO WITH FILES THAT WILL BE CONSIDERED"\r
1479 .TP\r
1480 .B -find\r
1481 (you can use\r
1482 .B -f\r
1483 as well).\r
1484 This option changes the basic action of\r
1485 .IR search .\r
1487 Normally, if a file is considered, it is searched\r
1488 for the regular expressions as described earlier. However, if this option\r
1489 is given, the filename is printed and no searching takes place. This turns\r
1490 .I search\r
1491 into a 'find' of some sorts.\r
1493 In this case, no regular expressions are needed on the command line\r
1494 (any that are there are silently ignored).\r
1496 This is not intended to be a replacement for the 'find' program,\r
1497 but to aid\r
1498 you in understanding just what files are getting past the exclusion checks.\r
1499 If you really want to use it as a sort of replacement for the 'find' program,\r
1500 you might want to use\r
1501 .B -all\r
1502 so that it doesn't waste time checking to see if the file is binary, etc\r
1503 (unless you really want that, of course).\r
1505 If you use\r
1506 .BR -find ,\r
1507 none of the "GREP-LIKE OPTIONS" (below) matter.\r
1509 As a replacement for 'find',\r
1510 .I search\r
1511 is probably a bit slower (or in the case of GNU find, a lot slower --\r
1512 GNU find is\r
1513 .I unbelievably\r
1514 fast).\r
1515 However, "search -ffind"\r
1516 might be more useful than 'find' when options such as\r
1517 .B -skip\r
1518 are used (at least until 'find' gets such functionality).\r
1519 .TP\r
1520 .B -ffind\r
1521 (or\r
1522 .BR -ff )\r
1523 A faster more 'find'-like find. Does\r
1524 .nf\r
1525     -find  -all -dorep\r
1526 .fi\r
1527 .SH "GREP-LIKE OPTIONS"\r
1528 These options control how a searched file is accessed,\r
1529 and how things are printed.\r
1530 .TP\r
1531 .B -i\r
1532 Ignore letter case when matching.\r
1533 .TP\r
1534 .B -w\r
1535 Consider only whole-word matches ("whole word" as defined by perl's "\\b"\r
1536 regex).\r
1537 .TP\r
1538 .B -u\r
1539 If the regex(es) is/are simple, try to modify them so that they'll work\r
1540 in manpage-like underlined text (i.e. like _^Ht_^Hh_^Hi_^Hs).\r
1541 This is very rudimentary at the moment.\r
1542 .TP\r
1543 .B -list\r
1544 (you can use\r
1545 .B -l\r
1546 too).\r
1547 Don't print matching lines, but the names of files that contain matching\r
1548 lines. This will likely be *much* faster, as special optimizations are\r
1549 made -- particularly with large files.\r
1550 .TP\r
1551 .B -n\r
1552 Pepfix each line by its line number.\r
1553 .TP\r
1554 .B -nice\r
1555 Not a grep-like option, but similar to\r
1556 .BR -list ,\r
1557 so included here.\r
1558 .B -nice\r
1559 will have the output be a bit more human-readable, with matching lines printed\r
1560 slightly indented after the filename, a'la\r
1561 .nf\r
1563    % search foo\r
1564    somedir/somefile: line with foo in it\r
1565    somedir/somefile: some food for thought\r
1566    anotherdir/x: don't be a buffoon!\r
1567    %\r
1569 .fi\r
1570 will become\r
1571 .nf\r
1573    % search -nice foo\r
1574    somedir/somefile:\r
1575      line with foo in it\r
1576      some food for thought\r
1577    anotherdir/x:\r
1578      don't be a buffoon!\r
1579    %\r
1581 .fi\r
1582 This option due to Lionel Cons.\r
1583 .TP\r
1584 .B -nnice\r
1585 Be a bit nicer than\r
1586 .BR -nice .\r
1587 Prefix each file's output by a rule line, and follow with an extra blank line.\r
1588 .TP\r
1589 .B -h\r
1590 Don't prepend each output line with the name of the file\r
1591 (meaningless when\r
1592 .B -find\r
1593 or\r
1594 .B -l\r
1595 are given).\r
1597 .SH "OTHER OPTIONS"\r
1598 .TP\r
1599 .B -help\r
1600 Print the usage information.\r
1601 .TP\r
1602 .B -version\r
1603 Print the version information and quit.\r
1604 .TP\r
1605 .B -v\r
1606 Set the level of message verbosity.\r
1607 .B -v\r
1608 will print a note whenever a new directory is entered.\r
1609 .B -vv\r
1610 will also print a note "every so often". This can be useful to see\r
1611 what's happening when searching huge directories.\r
1612 .B -vvv\r
1613 will print a new with every file.\r
1614 .B -vvvv\r
1615 is\r
1616 -vvv\r
1617 plus\r
1618 .BR -why .\r
1619 .TP\r
1620 .B -e\r
1621 This ends the options, and can be useful if the regex begins with '-'.\r
1622 .TP\r
1623 .B -showrc\r
1624 Shows what is being considered in the startup file, then exits.\r
1625 .TP\r
1626 .B -dorep\r
1627 Normally, an identical file won't be checked twice (even with multiple\r
1628 hard or symbolic links). If you're just trying to do a fast\r
1629 .BR -find ,\r
1630 the bookkeeping to remember which files have been seen is not desirable,\r
1631 so you can eliminate the bookkeeping with this flag.\r
1633 .SH "STARTUP FILE"\r
1634 When\r
1635 .I search\r
1636 starts up, it processes the directives in\r
1637 .IR ~/.search .\r
1638 If no such file exists, a default\r
1639 internal version is used.\r
1641 The internal version looks like:\r
1642 .nf\r
1644    magic: 32 : $H =~ m/[\ex00-\ex06\ex10-\ex1a\ex1c-\ex1f\ex80\exff]{2}/\r
1645    option: -skip '.a .COM .elc .EXE .gz .o .pbm .xbm .dvi'\r
1646    option: -iskip '.tarz .zip .z .lzh .jpg .jpeg .gif .uu'\r
1647    <!~> option: -skip '~ #'\r
1649 .fi\r
1650 If you wish to create your own "~/.search",\r
1651 you might consider copying the above, and then working from there.\r
1653 There are two kinds of directives in a startup file: "magic" and "option".\r
1654 .RS 0n\r
1655 .TP\r
1656 OPTION\r
1657 Option lines will automatically do the command-line options given.\r
1658 For example, the line\r
1659 .nf\r
1660         option: -v\r
1661 .fi\r
1662 in you startup file will turn on -v every time, without needing to type it\r
1663 on the command line.\r
1665 The text on the line after the "option:" directive is processed\r
1666 like the Bourne shell, so make sure to pay attention to quoting.\r
1667 .nf\r
1668         option: -skip .exe .com\r
1669 .fi\r
1670 will give an error (".com" by itself isn't a valid option), while\r
1671 .nf\r
1672         option: -skip ".exe .com"\r
1673 .fi\r
1674 will properly include it as part of -skip's argument.\r
1676 .TP\r
1677 MAGIC\r
1678 Magic lines are used to determine if a file should be considered a binary\r
1679 or not (the term "magic" refers to checking a file's magic number).  These\r
1680 are described in more detail below.\r
1681 .RE\r
1683 Blank lines and comments (lines beginning with '#') are allowed.\r
1685 If a line begins with  <...>, then it's a check to see if the\r
1686 directive on the line should be done or not. The stuff inside the <...>\r
1687 can contain perl's && (and), || (or), ! (not), and parens for grouping,\r
1688 along with "flags" that might be indicated by the user with\r
1689 .BI -x flag\r
1690 options.\r
1692 For example, using "-xfoo" will cause "foo" to be true inside the <...>\r
1693 blocks. Therefore, a line beginning with "<foo>" would be done only when\r
1694 "-xfoo" had been specified, while a line beginning with "<!foo>" would be\r
1695 done only when "-xfoo" is not specified (of course, a line without any <...>\r
1696 is done in either case).\r
1698 A realistic example might be\r
1699 .nf\r
1700         <!v> -vv\r
1701 .fi\r
1702 This will cause -vv messages to be the default, but allow "-xv" to override.\r
1704 There are a few flags that are set automatically:\r
1705 .RS\r
1706 .TP\r
1707 .B TTY\r
1708 true if the output is to the screen (as opposed to being redirected to a file).\r
1709 You can force this (as with all the other automatic flags) with -xTTY.\r
1710 .TP\r
1711 .B -v\r
1712 True if -v was specified. If -vv was specified, both \r
1713 .B -v\r
1714 and\r
1715 .B -vv\r
1716 flags are true (and so on).\r
1717 .TP\r
1718 .B -nice\r
1719 True if -nice was specified. Same thing about -nnice as for -vv.\r
1720 .PP\r
1721 .TP\r
1722 .B -list\r
1723 true if -list (or -l) was given.\r
1724 .TP\r
1725 .B -dir\r
1726 true if -dir was given.\r
1727 .RE\r
1729 Using this info, you might change the last example to\r
1730 .nf\r
1732     <!v && !-v> option: -vv\r
1734 .fi\r
1735 The added "&& !-v" means "and if the '-v' option not given".\r
1736 This will allow you to use "-v" alone on the command line, and not\r
1737 have this directive add the more verbose "-vv" automatically.\r
1739 .RS 0\r
1740 Some other examples:\r
1741 .TP\r
1742 <!-dir && !here> option: -dir ~/\r
1743 Effectively make the default directory your home directory (instead of the\r
1744 current directory). Using -dir or -xhere will undo this.\r
1745 .TP\r
1746 <tex> option: -name .tex -dir ~/pub\r
1747 Create '-xtex' to search only "*.tex" files in your ~/pub directory tree.\r
1748 Actually, this could be made a bit better. If you combine '-xtex' and '-dir'\r
1749 on the command line, this directive will add ~/pub to the list, when you\r
1750 probably want to use the -dir directory only. You could do\r
1751 .nf\r
1753    <tex> option: -name .tex\r
1754    <tex && !-dir> option: -dir ~/pub\r
1755 .fi\r
1757 to will allow '-xtex' to work as before, but allow a command-line "-dir"\r
1758 to take precedence with respect to ~/pub.\r
1759 .TP\r
1760 <fluff> option: -nnice -sort -i -vvv\r
1761 Combine a few user-friendly options into one '-xfluff' option.\r
1762 .TP\r
1763 <man> option: -ddir /usr/man -v -w\r
1764 When the '-xman' option is given, search "/usr/man" for whole-words\r
1765 (of whatever regex or regexes are given on the command line), with -v.\r
1766 .RE\r
1768 The lines in the startup file are executed from top to bottom, so something\r
1769 like\r
1770 .nf\r
1772    <both> option: -xflag1 -xflag2\r
1773    <flag1> option: ...whatever...\r
1774    <flag2> option: ...whatever...\r
1776 .fi\r
1777 will allow '-xboth' to be the same as '-xflag1 -xflag2' (or '-xflag1,flag2'\r
1778 for that matter). However, if you put the "<both>" line below the others,\r
1779 they will not be true when encountered, so the result would be different\r
1780 (and probably undesired).\r
1782 The "magic" directives are used to determine if a file looks to be binary\r
1783 or not. The form of a magic line is\r
1784 .nf\r
1785     magic: \fISIZE\fP : \fIPERLCODE\fP\r
1786 .fi\r
1787 where\r
1788 .I SIZE\r
1789 is the number of bytes of the file you need to check, and\r
1790 .I PERLCODE\r
1791 is the code to do the check. Within\r
1792 .IR PERLCODE ,\r
1793 the variable $H will hold at least the first\r
1794 .I SIZE\r
1795 bytes of the file (unless the file is shorter than that, of course).\r
1796 It might hold more bytes. The perl should evaluate to true if the file\r
1797 should be considered a binary.\r
1799 An example might be\r
1800 .nf\r
1801     magic: 6 : substr($H, 0, 6) eq 'GIF87a'\r
1802 .fi\r
1803 to test for a GIF ("-iskip .gif" is better, but this might be useful\r
1804 if you have images in files without the ".gif" extension).\r
1806 Since the startup file is checked from top to bottom, you can be a bit\r
1807 efficient:\r
1808 .nf\r
1809     magic: 6 : ($x6 = substr($H, 0, 6)) eq 'GIF87a'\r
1810     magic: 6 :  $x6                     eq 'GIF89a'\r
1811 .fi\r
1812 You could also write the same thing as\r
1813 .nf\r
1814   magic: 6 : (($x6 = substr($H, 0, 6)) eq 'GIF87a') || ## an old gif, or.. \e\r
1815                $x6                     eq 'GIF89a'     ## .. a new one.\r
1816 .fi\r
1817 since newlines may be escaped.\r
1819 The default internal startup file includes\r
1820 .nf\r
1821    magic: 32 : $H =~ m/[\ex00-\ex06\ex10-\ex1a\ex1c-\ex1f\ex80\exff]{2}/\r
1822 .fi\r
1823 which checks for certain non-printable characters, and catches a large\r
1824 number of binary files, including most system's executables, linkable\r
1825 objects, compressed, tarred, and otherwise folded, spindled, and mutilated\r
1826 files.\r
1828 Another example might be\r
1829 .nf\r
1830     ## an archive library\r
1831     magic: 17 : substr($H, 0, 17) eq "!<arch>\en__.SYMDEF"\r
1832 .fi\r
1834 .SH "RETURN VALUE"\r
1835 .I Search\r
1836 returns zero if lines (or files, if appropriate) were found,\r
1837 or if no work was requested (such as with\r
1838 .BR -help ).\r
1839 Returns 1 if no lines (or files) were found.\r
1840 Returns 2 on error.\r
1842 .SH TODO\r
1843 Things I'd like to add some day:\r
1844 .nf\r
1845   + show surrounding lines (context).\r
1846   + highlight matched portions of lines.\r
1847   + add '-and', which can go between regexes to override\r
1848     the default logical or of the regexes.\r
1849   + add something like\r
1850       -below GLOB\r
1851     which will examine a tree and only consider files that\r
1852     lie in a directory deeper than one named by the pattern.\r
1853   + add 'warning' and 'error' directives.\r
1854   + add 'help' directive.\r
1855 .fi\r
1856 .SH BUGS\r
1857 If -xdev and multiple -dir arguments are given, any file in any of the\r
1858 target filesystems are allowed. It would be better to allow each filesystem\r
1859 for each separate tree.\r
1861 Multiple -dir args might also cause some confusing effects. Doing\r
1862 .nf\r
1863    -dir some/dir -dir other\r
1864 .fi\r
1865 will search "some/dir" completely, then search "other" completely. This\r
1866 is good. However, something like\r
1867 .nf\r
1868    -dir some/dir -dir some/dir/more/specific\r
1869 .fi\r
1870 will search "some/dir" completely *except for* "some/dir/more/specific",\r
1871 after which it will return and be searched. Not really a bug, but just sort\r
1872 of odd.\r
1874 File times (for -newer, etc.) of symbolic links are for the file, not the\r
1875 link. This could cause some misunderstandings.\r
1877 Probably more. Please let me know.\r
1878 .SH AUTHOR\r
1879 Jeffrey Friedl, Omron Corp (jfriedl@omron.co.jp)\r
1880 .br\r
1881 http://www.wg.omron.co.jp/cgi-bin/j-e/jfriedl.html\r
1883 .SH "LATEST SOURCE"\r
1884 See http://www.wg.omron.co.jp/~jfriedl/perl/index.html\r
1886 __END__\r
1887 :endofperl\r