source: for-distributions/trunk/bin/windows/perl/bin/search.bat@ 14489

Last change on this file since 14489 was 14489, checked in by oranfry, 17 years ago

upgrading to perl 5.8

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