File Coverage

blib/lib/Pod/Simple/Search.pm
Criterion Covered Total %
statement 269 390 68.9
branch 111 258 43.0
condition 45 93 48.3
subroutine 30 38 78.9
pod 4 7 57.1
total 459 786 58.4


line stmt bran cond sub pod time code
1             package Pod::Simple::Search;
2 14     14   342354 use strict;
  14         111  
  14         452  
3 14     14   76 use warnings;
  14         27  
  14         1161  
4              
5             our $VERSION = '3.45'; ## Current version of this package
6              
7 14 50   14   340 BEGIN { *DEBUG = sub () {0} unless defined &DEBUG; } # set DEBUG level
8 14     14   79 use Carp ();
  14         33  
  14         1552  
9              
10             our $SLEEPY;
11             $SLEEPY = 1 if !defined $SLEEPY and $^O =~ /mswin|mac/i;
12             # flag to occasionally sleep for $SLEEPY - 1 seconds.
13              
14             our $MAX_VERSION_WITHIN ||= 60;
15              
16             #############################################################################
17              
18             #use diagnostics;
19 14     14   98 use File::Spec ();
  14         28  
  14         526  
20 14     14   85 use File::Basename qw( basename dirname );
  14         35  
  14         1636  
21 14     14   88 use Config ();
  14         29  
  14         367  
22 14     14   93 use Cwd qw( cwd );
  14         37  
  14         76252  
23              
24             #==========================================================================
25             __PACKAGE__->_accessorize( # Make my dumb accessor methods
26             'callback', 'progress', 'dir_prefix', 'inc', 'laborious', 'limit_glob',
27             'limit_re', 'shadows', 'verbose', 'name2path', 'path2name', 'recurse',
28             'ciseen', 'is_case_insensitive'
29             );
30             #==========================================================================
31              
32             sub new {
33 13     13 0 3666 my $class = shift;
34 13   33     180 my $self = bless {}, ref($class) || $class;
35 13         76 $self->init;
36 13         57 return $self;
37             }
38              
39             sub init {
40 13     13 0 35 my $self = shift;
41 13         66 $self->inc(1);
42 13         63 $self->recurse(1);
43 13         73 $self->verbose(DEBUG);
44 13   33     352 $self->is_case_insensitive(-e uc __FILE__ && -e lc __FILE__);
45 13         116 return $self;
46             }
47              
48             #--------------------------------------------------------------------------
49              
50             sub survey {
51 15     15 1 672 my($self, @search_dirs) = @_;
52 15 50       73 $self = $self->new unless ref $self; # tolerate being a class method
53              
54 15         103 $self->_expand_inc( \@search_dirs );
55              
56 15         55 $self->{'_scan_count'} = 0;
57 15         77 $self->{'_dirs_visited'} = {};
58 15         68 $self->path2name( {} );
59 15         75 $self->name2path( {} );
60 15         76 $self->ciseen( {} );
61 15 100       76 $self->limit_re( $self->_limit_glob_to_limit_re ) if $self->{'limit_glob'};
62 15         57599 my $cwd = cwd();
63 15         643 my $verbose = $self->verbose;
64 15         187 local $_; # don't clobber the caller's $_ !
65              
66 15         228 foreach my $try (@search_dirs) {
67 38 100       1154 unless( File::Spec->file_name_is_absolute($try) ) {
68             # make path absolute
69 1         11 $try = File::Spec->catfile( $cwd ,$try);
70             }
71             # simplify path
72 38         386 $try = File::Spec->canonpath($try);
73              
74 38         189 my $start_in;
75             my $modname_prefix;
76 38 100       284 if($self->{'dir_prefix'}) {
77             $start_in = File::Spec->catdir(
78             $try,
79 3         46 grep length($_), split '[\\/:]+', $self->{'dir_prefix'}
80             );
81 3         25 $modname_prefix = [grep length($_), split m{[:/\\]}, $self->{'dir_prefix'}];
82 3 50       21 $verbose and print "Appending \"$self->{'dir_prefix'}\" to $try, ",
83             "giving $start_in (= @$modname_prefix)\n";
84             } else {
85 35         159 $start_in = $try;
86             }
87              
88 38 50       284 if( $self->{'_dirs_visited'}{$start_in} ) {
89 0 0       0 $verbose and print "Directory '$start_in' already seen, skipping.\n";
90 0         0 next;
91             } else {
92 38         271 $self->{'_dirs_visited'}{$start_in} = 1;
93             }
94              
95 38 50       1018 unless(-e $start_in) {
96 0 0       0 $verbose and print "Skipping non-existent $start_in\n";
97 0         0 next;
98             }
99              
100 38         374 my $closure = $self->_make_search_callback;
101              
102 38 50       642 if(-d $start_in) {
    0          
103             # Normal case:
104 38 50       249 $verbose and print "Beginning excursion under $start_in\n";
105 38         275 $self->_recurse_dir( $start_in, $closure, $modname_prefix );
106 38 50       903 $verbose and print "Back from excursion under $start_in\n\n";
107              
108             } elsif(-f _) {
109             # A excursion consisting of just one file!
110 0         0 $_ = basename($start_in);
111 0 0       0 $verbose and print "Pondering $start_in ($_)\n";
112 0         0 $closure->($start_in, $_, 0, []);
113              
114             } else {
115 0 0       0 $verbose and print "Skipping mysterious $start_in\n";
116             }
117             }
118 15 50       73 $self->progress and $self->progress->done(
119             "Noted $$self{'_scan_count'} Pod files total");
120 15         242 $self->ciseen( {} );
121              
122 15 100       83 return unless defined wantarray; # void
123 14 50       74 return $self->name2path unless wantarray; # scalar
124 14         51 return $self->name2path, $self->path2name; # list
125             }
126              
127             #==========================================================================
128             sub _make_search_callback {
129 38     38   162 my $self = $_[0];
130              
131             # Put the options in variables, for easy access
132 38         322 my( $laborious, $verbose, $shadows, $limit_re, $callback, $progress,
133             $path2name, $name2path, $recurse, $ciseen, $is_case_insensitive) =
134             map scalar($self->$_()),
135             qw(laborious verbose shadows limit_re callback progress
136             path2name name2path recurse ciseen is_case_insensitive);
137 38         164 my ($seen, $remember, $files_for);
138 38 50       179 if ($is_case_insensitive) {
139 0     0   0 $seen = sub { $ciseen->{ lc $_[0] } };
  0         0  
140 0     0   0 $remember = sub { $name2path->{ $_[0] } = $ciseen->{ lc $_[0] } = $_[1]; };
  0         0  
141 0     0   0 $files_for = sub { my $n = lc $_[0]; grep { lc $path2name->{$_} eq $n } %{ $path2name } };
  0         0  
  0         0  
  0         0  
  0         0  
142             } else {
143 38     3197   583 $seen = sub { $name2path->{ $_[0] } };
  3197         13168  
144 38     1198   360 $remember = sub { $name2path->{ $_[0] } = $_[1] };
  1198         6789  
145 38     0   358 $files_for = sub { my $n = $_[0]; grep { $path2name->{$_} eq $n } %{ $path2name } };
  0         0  
  0         0  
  0         0  
  0         0  
146             }
147              
148 38         151 my($file, $shortname, $isdir, $modname_bits);
149             return sub {
150 4804     4804   12564 ($file, $shortname, $isdir, $modname_bits) = @_;
151              
152 4804 100       9959 if($isdir) { # this never gets called on the startdir itself, just subdirs
153              
154 685 100       1581 unless( $recurse ) {
155 16 50       109 $verbose and print "Not recursing into '$file' as per requested.\n";
156 16         82 return 'PRUNE';
157             }
158              
159 669 100       2245 if( $self->{'_dirs_visited'}{$file} ) {
160 4 50       14 $verbose and print "Directory '$file' already seen, skipping.\n";
161 4         22 return 'PRUNE';
162             }
163              
164 665 50       1310 print "Looking in dir $file\n" if $verbose;
165              
166 665 50       1271 unless ($laborious) { # $laborious overrides pruning
167 665 0 33     1833 if( m/^(\d+\.[\d_]{3,})\z/s
168 0         0 and do { my $x = $1; $x =~ tr/_//d; $x != $] }
  0         0  
  0         0  
169             ) {
170 0 0       0 $verbose and print "Perl $] version mismatch on $_, skipping.\n";
171 0         0 return 'PRUNE';
172             }
173              
174 665 100       3105 if( m/^([A-Za-z][a-zA-Z0-9_]*)\z/s ) {
175 608 50       1364 $verbose and print "$_ is a well-named module subdir. Looking....\n";
176             } else {
177 57 50       94 $verbose and print "$_ is a fishy directory name. Skipping.\n";
178 57         138 return 'PRUNE';
179             }
180             } # end unless $laborious
181              
182 608         2277 $self->{'_dirs_visited'}{$file} = 1;
183 608         2505 return; # (not pruning);
184             }
185              
186             # Make sure it's a file even worth even considering
187 4119 50       7208 if($laborious) {
188 0 0 0     0 unless(
      0        
189             m/\.(pod|pm|plx?)\z/i || -x _ and -T _
190             # Note that the cheapest operation (the RE) is run first.
191             ) {
192 0 0       0 $verbose > 1 and print " Brushing off uninteresting $file\n";
193 0         0 return;
194             }
195             } else {
196 4119 100       22536 unless( m/^[-_a-zA-Z0-9]+\.(?:pod|pm|plx?)\z/is ) {
197 2025 50       4122 $verbose > 1 and print " Brushing off oddly-named $file\n";
198 2025         3675 return;
199             }
200             }
201              
202 2094 50       5694 $verbose and print "Considering item $file\n";
203 2094         6752 my $name = $self->_path2modname( $file, $shortname, $modname_bits );
204 2094 50       5239 $verbose > 0.01 and print " Nominating $file as $name\n";
205              
206 2094 100 100     5306 if($limit_re and $name !~ m/$limit_re/i) {
207 62 50       139 $verbose and print "Shunning $name as not matching $limit_re\n";
208 62         141 return;
209             }
210              
211 2032 100 100     6699 if( !$shadows and $seen->($name) ) {
212 75 50       170 $verbose and print "Not worth considering $file ",
213             "-- already saw $name as ",
214             join(' ', $files_for->($name)), "\n";
215 75         171 return;
216             }
217              
218             # Put off until as late as possible the expense of
219             # actually reading the file:
220 1957 50       4001 $progress and $progress->reach($self->{'_scan_count'}, "Scanning $file");
221 1957 100       5379 return unless $self->contains_pod( $file );
222 1208         3589 ++ $self->{'_scan_count'};
223              
224             # Or finally take note of it:
225 1208 100       3212 if ( my $prev = $seen->($name) ) {
226 10 50       28 $verbose and print
227             "Duplicate POD found (shadowing?): $name ($file)\n",
228             " Already seen in ", join(' ', $files_for->($name)), "\n";
229             } else {
230 1198         2776 $remember->($name, $file); # Noting just the first occurrence
231             }
232 1208 50       3338 $verbose and print " Noting $name = $file\n";
233 1208 100       2834 if( $callback ) {
234 1131         2202 local $_ = $_; # insulate from changes, just in case
235 1131         3519 $callback->($file, $name);
236             }
237 1208         12146 $path2name->{$file} = $name;
238 1208         3579 return;
239             }
240 38         583 }
241              
242             #==========================================================================
243              
244             sub _path2modname {
245 2094     2094   4789 my($self, $file, $shortname, $modname_bits) = @_;
246              
247             # this code simplifies the POD name for Perl modules:
248             # * remove "site_perl"
249             # * remove e.g. "i586-linux" (from 'archname')
250             # * remove e.g. 5.00503
251             # * remove pod/ if followed by perl*.pod (e.g. in pod/perlfunc.pod)
252             # * dig into the file for case-preserved name if not already mixed case
253              
254 2094         6378 my @m = @$modname_bits;
255 2094         3178 my $x;
256 2094         5044 my $verbose = $self->verbose;
257              
258             # Shaving off leading naughty-bits
259 2094   66     36035 while(@m
      66        
      66        
260             and defined($x = lc( $m[0] ))
261             and( $x eq 'site_perl'
262             or($x =~ m/^pods?$/ and @m == 1 and $shortname =~ m{^perl.*\.pod$}s )
263             or $x =~ m{\\d+\\.z\\d+([_.]?\\d+)?} # if looks like a vernum
264             or $x eq lc( $Config::Config{'archname'} )
265 228         1047 )) { shift @m }
266              
267 2094         8770 my $name = join '::', @m, $shortname;
268 2094         6570 $self->_simplify_base($name);
269              
270             # On VMS, case-preserved document names can't be constructed from
271             # filenames, so try to extract them from the "=head1 NAME" tag in the
272             # file instead.
273 2094 0 0     4519 if ($^O eq 'VMS' && ($name eq lc($name) || $name eq uc($name))) {
      33        
274 0 0       0 open PODFILE, "<$file" or die "_path2modname: Can't open $file: $!";
275 0         0 my $in_pod = 0;
276 0         0 my $in_name = 0;
277 0         0 my $line;
278 0         0 while ($line = ) {
279 0         0 chomp $line;
280 0 0       0 $in_pod = 1 if ($line =~ m/^=\w/);
281 0 0       0 $in_pod = 0 if ($line =~ m/^=cut/);
282 0 0       0 next unless $in_pod; # skip non-pod text
283 0 0       0 next if ($line =~ m/^\s*\z/); # and blank lines
284 0 0 0     0 next if ($in_pod && ($line =~ m/^X
285 0 0       0 if ($in_name) {
286 0 0       0 if ($line =~ m/(\w+::)?(\w+)/) {
287             # substitute case-preserved version of name
288 0         0 my $podname = $2;
289 0   0     0 my $prefix = $1 || '';
290 0 0       0 $verbose and print "Attempting case restore of '$name' from '$prefix$podname'\n";
291 0 0       0 unless ($name =~ s/$prefix$podname/$prefix$podname/i) {
292 0 0       0 $verbose and print "Attempting case restore of '$name' from '$podname'\n";
293 0         0 $name =~ s/$podname/$podname/i;
294             }
295 0         0 last;
296             }
297             }
298 0 0       0 $in_name = 1 if ($line =~ m/^=head1 NAME/);
299             }
300 0         0 close PODFILE;
301             }
302              
303 2094         5904 return $name;
304             }
305              
306             #==========================================================================
307              
308             sub _recurse_dir {
309 38     38   175 my($self, $startdir, $callback, $modname_bits) = @_;
310              
311 38   50     342 my $maxdepth = $self->{'fs_recursion_maxdepth'} || 10;
312 38         151 my $verbose = $self->verbose;
313              
314 38         526 my $here_string = File::Spec->curdir;
315 38         4657 my $up_string = File::Spec->updir;
316 38   100     358 $modname_bits ||= [];
317              
318 38         70 my $recursor;
319             $recursor = sub {
320 646     646   1688 my($dir_long, $dir_bare) = @_;
321 646 50       1535 if( @$modname_bits >= 10 ) {
322 0 0       0 $verbose and print "Too deep! [@$modname_bits]\n";
323 0         0 return;
324             }
325              
326 646 50       8943 unless(-d $dir_long) {
327 0 0       0 $verbose > 2 and print "But it's not a dir! $dir_long\n";
328 0         0 return;
329             }
330 646 50       17394 unless( opendir(INDIR, $dir_long) ) {
331 0 0       0 $verbose > 2 and print "Can't opendir $dir_long : $!\n";
332 0         0 closedir(INDIR);
333             return
334 0         0 }
335              
336             # Load all items; put no extension before .pod before .pm before .plx?.
337 6096         11156 my @items = map { $_->[0] }
338 27108 50       48216 sort { $a->[1] cmp $b->[1] || $b->[2] cmp $a->[2] }
339             map {
340 646         20888 (my $t = $_) =~ s/[.]p(m|lx?|od)\z//;
  6096         16991  
341 6096   100     29516 [$_, $t, lc($1 || 'z') ]
342             } readdir(INDIR);
343 646         8981 closedir(INDIR);
344              
345 646 100       3002 push @$modname_bits, $dir_bare unless $dir_bare eq '';
346              
347 646         1430 my $i_full;
348 646         1423 foreach my $i (@items) {
349 6096 100 100     27948 next if $i eq $here_string or $i eq $up_string or $i eq '';
      66        
350 4804         49040 $i_full = File::Spec->catfile( $dir_long, $i );
351              
352 4804 50       180176 if(!-r $i_full) {
    100          
    50          
353 0 0       0 $verbose and print "Skipping unreadable $i_full\n";
354              
355             } elsif(-f $i_full) {
356 4119         12447 $_ = $i;
357 4119         10799 $callback->( $i_full, $i, 0, $modname_bits );
358              
359             } elsif(-d _) {
360 685 50       3214 $i =~ s/\.DIR\z//i if $^O eq 'VMS';
361 685         1720 $_ = $i;
362 685   100     1756 my $rv = $callback->( $i_full, $i, 1, $modname_bits ) || '';
363              
364 685 100       1511 if($rv eq 'PRUNE') {
365 77 50       224 $verbose > 1 and print "OK, pruning";
366             } else {
367             # Otherwise, recurse into it
368 608         4469 $recursor->( File::Spec->catdir($dir_long, $i) , $i);
369             }
370             } else {
371 0 0       0 $verbose > 1 and print "Skipping oddity $i_full\n";
372             }
373             }
374 646         1127 pop @$modname_bits;
375 646         2709 return;
376 38         492 };;
377              
378 38         100 local $_;
379 38         229 $recursor->($startdir, '');
380              
381 38         759 undef $recursor; # allow it to be GC'd
382              
383 38         107 return;
384             }
385              
386              
387             #==========================================================================
388              
389             sub run {
390             # A function, useful in one-liners
391              
392 0     0 0 0 my $self = __PACKAGE__->new;
393 0 0       0 $self->limit_glob($ARGV[0]) if @ARGV;
394             $self->callback( sub {
395 0     0   0 my($file, $name) = @_;
396 0         0 my $version = '';
397              
398             # Yes, I know we won't catch the version in like a File/Thing.pm
399             # if we see File/Thing.pod first. That's just the way the
400             # cookie crumbles. -- SMB
401              
402 0 0       0 if($file =~ m/\.pod$/i) {
    0          
403             # Don't bother looking for $VERSION in .pod files
404 0         0 DEBUG and print "Not looking for \$VERSION in .pod $file\n";
405             } elsif( !open(INPOD, $file) ) {
406 0         0 DEBUG and print "Couldn't open $file: $!\n";
407 0         0 close(INPOD);
408             } else {
409             # Sane case: file is readable
410 0         0 my $lines = 0;
411 0         0 while() {
412 0 0       0 last if $lines++ > $MAX_VERSION_WITHIN; # some degree of sanity
413 0 0 0     0 if( s/^\s*\$VERSION\s*=\s*//s and m/\d/ ) {
414 0         0 DEBUG and print "Found version line (#$lines): $_";
415 0         0 s/\s*\#.*//s;
416 0         0 s/\;\s*$//s;
417 0         0 s/\s+$//s;
418 0         0 s/\t+/ /s; # nix tabs
419             # Optimize the most common cases:
420 0 0 0     0 $_ = "v$1"
421             if m{^v?["']?([0-9_]+(\.[0-9_]+)*)["']?$}s
422             # like in $VERSION = "3.14159";
423             or m{\$Revision:\s*([0-9_]+(?:\.[0-9_]+)*)\s*\$}s
424             # like in sprintf("%d.%02d", q$Revision: 4.13 $ =~ /(\d+)\.(\d+)/);
425             ;
426              
427             # Like in sprintf("%d.%s", map {s/_//g; $_} q$Name: release-0_55-public $ =~ /-(\d+)_([\d_]+)/)
428             $_ = sprintf("v%d.%s",
429 0 0       0 map {s/_//g; $_}
  0         0  
  0         0  
430             $1 =~ m/-(\d+)_([\d_]+)/) # snare just the numeric part
431             if m{\$Name:\s*([^\$]+)\$}s
432             ;
433 0         0 $version = $_;
434 0         0 DEBUG and print "Noting $version as version\n";
435 0         0 last;
436             }
437             }
438 0         0 close(INPOD);
439             }
440 0         0 print "$name\t$version\t$file\n";
441 0         0 return;
442             # End of callback!
443 0         0 });
444              
445 0         0 $self->survey;
446             }
447              
448             #==========================================================================
449              
450             sub simplify_name {
451 0     0 1 0 my($self, $str) = @_;
452              
453             # Remove all path components
454             # XXX Why not just use basename()? -- SMB
455              
456 0 0       0 if ($^O eq 'MacOS') { $str =~ s{^.*:+}{}s }
  0         0  
457 0         0 else { $str =~ s{^.*/+}{}s }
458              
459 0         0 $self->_simplify_base($str);
460 0         0 return $str;
461             }
462              
463             #==========================================================================
464              
465             sub _simplify_base { # Internal method only
466              
467             # strip Perl's own extensions
468 2094     2094   11851 $_[1] =~ s/\.(pod|pm|plx?)\z//i;
469              
470             # strip meaningless extensions on Win32 and OS/2
471 2094 50       12339 $_[1] =~ s/\.(bat|exe|cmd)\z//i if $^O =~ /mswin|os2/i;
472              
473             # strip meaningless extensions on VMS
474 2094 50       5508 $_[1] =~ s/\.(com)\z//i if $^O eq 'VMS';
475              
476 2094         3179 return;
477             }
478              
479             #==========================================================================
480              
481             sub _expand_inc {
482 1130     1130   2037 my($self, $search_dirs) = @_;
483              
484 1130 100       2507 return unless $self->{'inc'};
485 1115         1533 my %seen = map { File::Spec->rel2abs($_) => 1 } @{ $search_dirs };
  0         0  
  1115         2105  
486              
487 1115 50       3598 if ($^O eq 'MacOS') {
488             push @$search_dirs,
489 0         0 grep { !$seen{ File::Spec->rel2abs($_) }++ } $self->_mac_whammy(@INC);
  0         0  
490             # Any other OSs need custom handling here?
491             } else {
492             push @$search_dirs,
493 1115         2436 grep { !$seen{ File::Spec->rel2abs($_) }++ } @INC;
  12265         90759  
494             }
495              
496 1115         3218 $self->{'laborious'} = 0; # Since inc said to use INC
497 1115         3191 return;
498             }
499              
500             #==========================================================================
501              
502             sub _mac_whammy { # Tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
503 0     0   0 my @them;
504 0         0 (undef,@them) = @_;
505 0         0 for $_ (@them) {
506 0 0       0 if ( $_ eq '.' ) {
    0          
507 0         0 $_ = ':';
508 0         0 } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
509 0         0 $_ = ':'. $_;
510             } else {
511 0         0 $_ =~ s|^\./|:|;
512             }
513             }
514 0         0 return @them;
515             }
516              
517             #==========================================================================
518              
519             sub _limit_glob_to_limit_re {
520 5     5   14 my $self = $_[0];
521 5   50     28 my $limit_glob = $self->{'limit_glob'} || return;
522              
523 5         26 my $limit_re = '^' . quotemeta($limit_glob) . '$';
524 5         19 $limit_re =~ s/\\\?/./g; # glob "?" => "."
525 5         22 $limit_re =~ s/\\\*/.*?/g; # glob "*" => ".*?"
526 5         22 $limit_re =~ s/\.\*\?\$$//s; # final glob "*" => ".*?$" => ""
527              
528 5 50       21 $self->{'verbose'} and print "Turning limit_glob $limit_glob into re $limit_re\n";
529              
530             # A common optimization:
531 5 100 66     53 if(!exists($self->{'dir_prefix'})
532             and $limit_glob =~ m/^(?:\w+\:\:)+/s # like "File::*" or "File::Thing*"
533             # Optimize for sane and common cases (but not things like "*::File")
534             ) {
535 1         8 $self->{'dir_prefix'} = join "::", $limit_glob =~ m/^(?:\w+::)+/sg;
536 1 50       7 $self->{'verbose'} and print " and setting dir_prefix to $self->{'dir_prefix'}\n";
537             }
538              
539 5         24 return $limit_re;
540             }
541              
542             #==========================================================================
543              
544             # contribution mostly from Tim Jenness
545              
546             sub _actual_filenames {
547 18012     18012   40399 my $dir = shift;
548 18012         28069 my $fn = lc shift;
549 18012 50       403181 opendir my ($dh), $dir or return;
550 2369         47207 return map { File::Spec->catdir($dir, $_) }
551 18012         607139 grep { lc $_ eq $fn } readdir $dh;
  319484         734800  
552             }
553              
554             sub find {
555 1115     1115 1 684119 my($self, $pod, @search_dirs) = @_;
556 1115 50       3322 $self = $self->new unless ref $self; # tolerate being a class method
557              
558             # Check usage
559 1115 50 33     4715 Carp::carp 'Usage: \$self->find($podname, ...)'
560             unless defined $pod and length $pod;
561              
562 1115         2635 my $verbose = $self->verbose;
563              
564             # Split on :: and then join the name together using File::Spec
565 1115         4024 my @parts = split /::/, $pod;
566 1115 50       2355 $verbose and print "Chomping {$pod} => {@parts}\n";
567              
568             #@search_dirs = File::Spec->curdir unless @search_dirs;
569              
570 1115         3347 $self->_expand_inc(\@search_dirs);
571             # Add location of binaries such as pod2text:
572 1115 100       3197 push @search_dirs, $Config::Config{'scriptdir'} if $self->inc;
573              
574 1115         2757 my %seen_dir;
575 1115         2781 while (my $dir = shift @search_dirs ) {
576 10121 50 33     42133 next unless defined $dir and length $dir;
577 10121 50       23624 next if $seen_dir{$dir};
578 10121         18602 $seen_dir{$dir} = 1;
579 10121 50       122556 unless(-d $dir) {
580 0 0       0 print "Directory $dir does not exist\n" if $verbose;
581             }
582              
583 10121 50       27577 print "Looking in directory $dir\n" if $verbose;
584 10121         110958 my $fullname = File::Spec->catfile( $dir, @parts );
585 10121 50       27792 print "Filename is now $fullname\n" if $verbose;
586              
587 10121         19694 foreach my $ext ('', '.pod', '.pm', '.pl') { # possible extensions
588 39071         93083 my $fullext = $fullname . $ext;
589 39071 100 100     496486 if ( -f $fullext and $self->contains_pod($fullext) ) {
590 1115 50       2562 print "FOUND: $fullext\n" if $verbose;
591 1115 50 100     5248 if (@parts > 1 && lc $parts[0] eq 'pod' && $self->is_case_insensitive() && $ext eq '.pod') {
      66        
      33        
592             # Well, this file could be for a program (perldoc) but we actually
593             # want a module (Pod::Perldoc). So see if there is a .pm with the
594             # proper casing.
595 0         0 my $subdir = dirname $fullext;
596 0 0       0 unless (grep { $fullext eq $_ } _actual_filenames $subdir, "$parts[-1].pod") {
  0         0  
597 0 0       0 print "# Looking for alternate spelling in $subdir\n" if $verbose;
598             # Try the .pm file.
599 0         0 my $pm = $fullname . '.pm';
600 0 0 0     0 if ( -f $pm and $self->contains_pod($pm) ) {
601             # Prefer the .pm if its case matches.
602 0 0       0 if (grep { $pm eq $_ } _actual_filenames $subdir, "$parts[-1].pm") {
  0         0  
603 0 0       0 print "FOUND: $fullext\n" if $verbose;
604 0         0 return $pm;
605             }
606             }
607             }
608             }
609 1115         6705 return $fullext;
610             }
611             }
612              
613             # Case-insensitively Look for ./pod directories and slip them in.
614 9006         25377 for my $subdir ( _actual_filenames($dir, 'pods'), _actual_filenames($dir, 'pod') ) {
615 2369 50       31795 if (-d $subdir) {
616 2369 50       6528 $verbose and print "Noticing $subdir and looking there...\n";
617 2369         16898 unshift @search_dirs, $subdir;
618             }
619             }
620             }
621              
622 0         0 return undef;
623             }
624              
625             #==========================================================================
626              
627             sub contains_pod {
628 3073     3073 1 8025 my($self, $file) = @_;
629 3073         6100 my $verbose = $self->{'verbose'};
630              
631             # check for one line of POD
632 3073 50       6308 $verbose > 1 and print " Scanning $file for pod...\n";
633 3073 50       118291 unless( open(MAYBEPOD,"<$file") ) {
634 0         0 print "Error: $file is unreadable: $!\n";
635 0         0 return undef;
636             }
637              
638 3073 50       13525 sleep($SLEEPY - 1) if $SLEEPY;
639             # avoid totally hogging the processor on OSs with poor process control
640              
641 3073         5623 local $_;
642 3073         796914 while( ) {
643 823793 100       1856501 if(m/^=(head\d|pod|over|item)\b/s) {
644 2323 50       39796 close(MAYBEPOD) || die "Bizarre error closing $file: $!\nAborting";
645 2323         8466 chomp;
646 2323 50       5123 $verbose > 1 and print " Found some pod ($_) in $file\n";
647 2323         12071 return 1;
648             }
649             }
650 750 50       9693 close(MAYBEPOD) || die "Bizarre error closing $file: $!\nAborting";
651 750 50       2239 $verbose > 1 and print " No POD in $file, skipping.\n";
652 750         4743 return 0;
653             }
654              
655             #==========================================================================
656              
657             sub _accessorize { # A simple-minded method-maker
658 14     14   26 shift;
659 14     14   140 no strict 'refs';
  14         45  
  14         960  
660 14         34 foreach my $attrname (@_) {
661 196         797 *{caller() . '::' . $attrname} = sub {
662 14     14   92 use strict;
  14         38  
  14         5721  
663 5044 50 66 5044   51170 $Carp::CarpLevel = 1, Carp::croak(
      33        
664             "Accessor usage: \$obj->$attrname() or \$obj->$attrname(\$new_value)"
665             ) unless (@_ == 1 or @_ == 2) and ref $_[0];
666              
667             # Read access:
668 5044 100       24703 return $_[0]->{$attrname} if @_ == 1;
669              
670             # Write access:
671 147         461 $_[0]->{$attrname} = $_[1];
672 147         237 return $_[0]; # RETURNS MYSELF!
673 196         547 };
674             }
675             # Ya know, they say accessories make the ensemble!
676 14         38 return;
677             }
678              
679             #==========================================================================
680             sub _state_as_string {
681 11     11   8189 my $self = $_[0];
682 11 50       62 return '' unless ref $self;
683 11         78 my @out = "{\n # State of $self ...\n";
684 11         80 foreach my $k (sort keys %$self) {
685 51         116 push @out, " ", _esc($k), " => ", _esc($self->{$k}), ",\n";
686             }
687 11         47 push @out, "}\n";
688 11         59 my $x = join '', @out;
689 11         134 $x =~ s/^/#/mg;
690 11         2811 return $x;
691             }
692              
693             sub _esc {
694 102     102   151 my $in = $_[0];
695 102 100       210 return 'undef' unless defined $in;
696 91         185 $in =~
697 2         15 s<([^\x20\x21\x23\x27-\x3F\x41-\x5B\x5D-\x7E])>
698 91         295 <'\\x'.(unpack("H2",$1))>eg;
699             return qq{"$in"};
700             }
701              
702             #==========================================================================
703              
704             run() unless caller; # run if "perl whatever/Search.pm"
705              
706             1;
707              
708             #==========================================================================
709              
710             __END__