xref: /openbsd-src/gnu/usr.bin/perl/cpan/Pod-Simple/lib/Pod/Simple/Search.pm (revision de8cc8edbc71bd3e3bc7fbffa27ba0e564c37d8b)
1require 5.005;
2package Pod::Simple::Search;
3use strict;
4
5use vars qw($VERSION $MAX_VERSION_WITHIN $SLEEPY);
6$VERSION = '3.35';   ## Current version of this package
7
8BEGIN { *DEBUG = sub () {0} unless defined &DEBUG; }   # set DEBUG level
9use Carp ();
10
11$SLEEPY = 1 if !defined $SLEEPY and $^O =~ /mswin|mac/i;
12  # flag to occasionally sleep for $SLEEPY - 1 seconds.
13
14$MAX_VERSION_WITHIN ||= 60;
15my $IS_CASE_INSENSITIVE = -e uc __FILE__ && -e lc __FILE__;
16
17#############################################################################
18
19#use diagnostics;
20use File::Spec ();
21use File::Basename qw( basename dirname );
22use Config ();
23use Cwd qw( cwd );
24
25#==========================================================================
26__PACKAGE__->_accessorize(  # Make my dumb accessor methods
27 'callback', 'progress', 'dir_prefix', 'inc', 'laborious', 'limit_glob',
28 'limit_re', 'shadows', 'verbose', 'name2path', 'path2name', 'recurse',
29 'ciseen'
30);
31#==========================================================================
32
33sub new {
34  my $class = shift;
35  my $self = bless {}, ref($class) || $class;
36  $self->init;
37  return $self;
38}
39
40sub init {
41  my $self = shift;
42  $self->inc(1);
43  $self->recurse(1);
44  $self->verbose(DEBUG);
45  return $self;
46}
47
48#--------------------------------------------------------------------------
49
50sub survey {
51  my($self, @search_dirs) = @_;
52  $self = $self->new unless ref $self; # tolerate being a class method
53
54  $self->_expand_inc( \@search_dirs );
55
56  $self->{'_scan_count'} = 0;
57  $self->{'_dirs_visited'} = {};
58  $self->path2name( {} );
59  $self->name2path( {} );
60  $self->ciseen( {} );
61  $self->limit_re( $self->_limit_glob_to_limit_re ) if $self->{'limit_glob'};
62  my $cwd = cwd();
63  my $verbose  = $self->verbose;
64  local $_; # don't clobber the caller's $_ !
65
66  foreach my $try (@search_dirs) {
67    unless( File::Spec->file_name_is_absolute($try) ) {
68      # make path absolute
69      $try = File::Spec->catfile( $cwd ,$try);
70    }
71    # simplify path
72    $try =  File::Spec->canonpath($try);
73
74    my $start_in;
75    my $modname_prefix;
76    if($self->{'dir_prefix'}) {
77      $start_in = File::Spec->catdir(
78        $try,
79        grep length($_), split '[\\/:]+', $self->{'dir_prefix'}
80      );
81      $modname_prefix = [grep length($_), split m{[:/\\]}, $self->{'dir_prefix'}];
82      $verbose and print "Appending \"$self->{'dir_prefix'}\" to $try, ",
83        "giving $start_in (= @$modname_prefix)\n";
84    } else {
85      $start_in = $try;
86    }
87
88    if( $self->{'_dirs_visited'}{$start_in} ) {
89      $verbose and print "Directory '$start_in' already seen, skipping.\n";
90      next;
91    } else {
92      $self->{'_dirs_visited'}{$start_in} = 1;
93    }
94
95    unless(-e $start_in) {
96      $verbose and print "Skipping non-existent $start_in\n";
97      next;
98    }
99
100    my $closure = $self->_make_search_callback;
101
102    if(-d $start_in) {
103      # Normal case:
104      $verbose and print "Beginning excursion under $start_in\n";
105      $self->_recurse_dir( $start_in, $closure, $modname_prefix );
106      $verbose and print "Back from excursion under $start_in\n\n";
107
108    } elsif(-f _) {
109      # A excursion consisting of just one file!
110      $_ = basename($start_in);
111      $verbose and print "Pondering $start_in ($_)\n";
112      $closure->($start_in, $_, 0, []);
113
114    } else {
115      $verbose and print "Skipping mysterious $start_in\n";
116    }
117  }
118  $self->progress and $self->progress->done(
119   "Noted $$self{'_scan_count'} Pod files total");
120  $self->ciseen( {} );
121
122  return unless defined wantarray; # void
123  return $self->name2path unless wantarray; # scalar
124  return $self->name2path, $self->path2name; # list
125}
126
127#==========================================================================
128sub _make_search_callback {
129  my $self = $_[0];
130
131  # Put the options in variables, for easy access
132  my( $laborious, $verbose, $shadows, $limit_re, $callback, $progress,
133      $path2name, $name2path, $recurse, $ciseen) =
134    map scalar($self->$_()),
135     qw(laborious verbose shadows limit_re callback progress
136        path2name name2path recurse ciseen);
137  my ($seen, $remember, $files_for);
138  if ($IS_CASE_INSENSITIVE) {
139      $seen      = sub { $ciseen->{ lc $_[0] } };
140      $remember  = sub { $name2path->{ $_[0] } = $ciseen->{ lc $_[0] } = $_[1]; };
141      $files_for = sub { my $n = lc $_[0]; grep { lc $path2name->{$_} eq $n } %{ $path2name } };
142  } else {
143      $seen      = sub { $name2path->{ $_[0] } };
144      $remember  = sub { $name2path->{ $_[0] } = $_[1] };
145      $files_for = sub { my $n = $_[0]; grep { $path2name->{$_} eq $n } %{ $path2name } };
146  }
147
148  my($file, $shortname, $isdir, $modname_bits);
149  return sub {
150    ($file, $shortname, $isdir, $modname_bits) = @_;
151
152    if($isdir) { # this never gets called on the startdir itself, just subdirs
153
154      unless( $recurse ) {
155        $verbose and print "Not recursing into '$file' as per requested.\n";
156        return 'PRUNE';
157      }
158
159      if( $self->{'_dirs_visited'}{$file} ) {
160        $verbose and print "Directory '$file' already seen, skipping.\n";
161        return 'PRUNE';
162      }
163
164      print "Looking in dir $file\n" if $verbose;
165
166      unless ($laborious) { # $laborious overrides pruning
167        if( m/^(\d+\.[\d_]{3,})\z/s
168             and do { my $x = $1; $x =~ tr/_//d; $x != $] }
169           ) {
170          $verbose and print "Perl $] version mismatch on $_, skipping.\n";
171          return 'PRUNE';
172        }
173
174        if( m/^([A-Za-z][a-zA-Z0-9_]*)\z/s ) {
175          $verbose and print "$_ is a well-named module subdir.  Looking....\n";
176        } else {
177          $verbose and print "$_ is a fishy directory name.  Skipping.\n";
178          return 'PRUNE';
179        }
180      } # end unless $laborious
181
182      $self->{'_dirs_visited'}{$file} = 1;
183      return; # (not pruning);
184    }
185
186    # Make sure it's a file even worth even considering
187    if($laborious) {
188      unless(
189        m/\.(pod|pm|plx?)\z/i || -x _ and -T _
190         # Note that the cheapest operation (the RE) is run first.
191      ) {
192        $verbose > 1 and print " Brushing off uninteresting $file\n";
193        return;
194      }
195    } else {
196      unless( m/^[-_a-zA-Z0-9]+\.(?:pod|pm|plx?)\z/is ) {
197        $verbose > 1 and print " Brushing off oddly-named $file\n";
198        return;
199      }
200    }
201
202    $verbose and print "Considering item $file\n";
203    my $name = $self->_path2modname( $file, $shortname, $modname_bits );
204    $verbose > 0.01 and print " Nominating $file as $name\n";
205
206    if($limit_re and $name !~ m/$limit_re/i) {
207      $verbose and print "Shunning $name as not matching $limit_re\n";
208      return;
209    }
210
211    if( !$shadows and $seen->($name) ) {
212      $verbose and print "Not worth considering $file ",
213        "-- already saw $name as ",
214        join(' ', $files_for->($name)), "\n";
215      return;
216    }
217
218    # Put off until as late as possible the expense of
219    #  actually reading the file:
220    $progress and $progress->reach($self->{'_scan_count'}, "Scanning $file");
221    return unless $self->contains_pod( $file );
222    ++ $self->{'_scan_count'};
223
224    # Or finally take note of it:
225    if ( my $prev = $seen->($name)  ) {
226      $verbose and print
227       "Duplicate POD found (shadowing?): $name ($file)\n",
228       "    Already seen in ", join(' ', $files_for->($name)), "\n";
229    } else {
230      $remember->($name, $file); # Noting just the first occurrence
231    }
232    $verbose and print "  Noting $name = $file\n";
233    if( $callback ) {
234      local $_ = $_; # insulate from changes, just in case
235      $callback->($file, $name);
236    }
237    $path2name->{$file} = $name;
238    return;
239  }
240}
241
242#==========================================================================
243
244sub _path2modname {
245  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  my @m = @$modname_bits;
255  my $x;
256  my $verbose = $self->verbose;
257
258  # Shaving off leading naughty-bits
259  while(@m
260    and defined($x = lc( $m[0] ))
261    and(  $x eq 'site_perl'
262       or($x eq 'pod' 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  )) { shift @m }
266
267  my $name = join '::', @m, $shortname;
268  $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  if ($^O eq 'VMS' && ($name eq lc($name) || $name eq uc($name))) {
274      open PODFILE, "<$file" or die "_path2modname: Can't open $file: $!";
275      my $in_pod = 0;
276      my $in_name = 0;
277      my $line;
278      while ($line = <PODFILE>) {
279        chomp $line;
280        $in_pod = 1 if ($line =~ m/^=\w/);
281        $in_pod = 0 if ($line =~ m/^=cut/);
282        next unless $in_pod;         # skip non-pod text
283        next if ($line =~ m/^\s*\z/);           # and blank lines
284        next if ($in_pod && ($line =~ m/^X</)); # and commands
285        if ($in_name) {
286          if ($line =~ m/(\w+::)?(\w+)/) {
287            # substitute case-preserved version of name
288            my $podname = $2;
289            my $prefix = $1 || '';
290            $verbose and print "Attempting case restore of '$name' from '$prefix$podname'\n";
291            unless ($name =~ s/$prefix$podname/$prefix$podname/i) {
292              $verbose and print "Attempting case restore of '$name' from '$podname'\n";
293              $name =~ s/$podname/$podname/i;
294            }
295            last;
296          }
297        }
298        $in_name = 1 if ($line =~ m/^=head1 NAME/);
299    }
300    close PODFILE;
301  }
302
303  return $name;
304}
305
306#==========================================================================
307
308sub _recurse_dir {
309  my($self, $startdir, $callback, $modname_bits) = @_;
310
311  my $maxdepth = $self->{'fs_recursion_maxdepth'} || 10;
312  my $verbose = $self->verbose;
313
314  my $here_string = File::Spec->curdir;
315  my $up_string   = File::Spec->updir;
316  $modname_bits ||= [];
317
318  my $recursor;
319  $recursor = sub {
320    my($dir_long, $dir_bare) = @_;
321    if( @$modname_bits >= 10 ) {
322      $verbose and print "Too deep! [@$modname_bits]\n";
323      return;
324    }
325
326    unless(-d $dir_long) {
327      $verbose > 2 and print "But it's not a dir! $dir_long\n";
328      return;
329    }
330    unless( opendir(INDIR, $dir_long) ) {
331      $verbose > 2 and print "Can't opendir $dir_long : $!\n";
332      closedir(INDIR);
333      return
334    }
335
336    # Load all items; put no extension before .pod before .pm before .plx?.
337    my @items = map { $_->[0] }
338      sort { $a->[1] cmp $b->[1] || $b->[2] cmp $a->[2] }
339      map {
340        (my $t = $_) =~ s/[.]p(m|lx?|od)\z//;
341        [$_, $t, lc($1 || 'z') ]
342      } readdir(INDIR);
343    closedir(INDIR);
344
345    push @$modname_bits, $dir_bare unless $dir_bare eq '';
346
347    my $i_full;
348    foreach my $i (@items) {
349      next if $i eq $here_string or $i eq $up_string or $i eq '';
350      $i_full = File::Spec->catfile( $dir_long, $i );
351
352      if(!-r $i_full) {
353        $verbose and print "Skipping unreadable $i_full\n";
354
355      } elsif(-f $i_full) {
356        $_ = $i;
357        $callback->(          $i_full, $i, 0, $modname_bits );
358
359      } elsif(-d _) {
360        $i =~ s/\.DIR\z//i if $^O eq 'VMS';
361        $_ = $i;
362        my $rv = $callback->( $i_full, $i, 1, $modname_bits ) || '';
363
364        if($rv eq 'PRUNE') {
365          $verbose > 1 and print "OK, pruning";
366        } else {
367          # Otherwise, recurse into it
368          $recursor->( File::Spec->catdir($dir_long, $i) , $i);
369        }
370      } else {
371        $verbose > 1 and print "Skipping oddity $i_full\n";
372      }
373    }
374    pop @$modname_bits;
375    return;
376  };;
377
378  local $_;
379  $recursor->($startdir, '');
380
381  undef $recursor;  # allow it to be GC'd
382
383  return;
384}
385
386
387#==========================================================================
388
389sub run {
390  # A function, useful in one-liners
391
392  my $self = __PACKAGE__->new;
393  $self->limit_glob($ARGV[0]) if @ARGV;
394  $self->callback( sub {
395    my($file, $name) = @_;
396    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    if($file =~ m/\.pod$/i) {
403      # Don't bother looking for $VERSION in .pod files
404      DEBUG and print "Not looking for \$VERSION in .pod $file\n";
405    } elsif( !open(INPOD, $file) ) {
406      DEBUG and print "Couldn't open $file: $!\n";
407      close(INPOD);
408    } else {
409      # Sane case: file is readable
410      my $lines = 0;
411      while(<INPOD>) {
412        last if $lines++ > $MAX_VERSION_WITHIN; # some degree of sanity
413        if( s/^\s*\$VERSION\s*=\s*//s and m/\d/ ) {
414          DEBUG and print "Found version line (#$lines): $_";
415          s/\s*\#.*//s;
416          s/\;\s*$//s;
417          s/\s+$//s;
418          s/\t+/ /s; # nix tabs
419          # Optimize the most common cases:
420          $_ = "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            map {s/_//g; $_}
430              $1 =~ m/-(\d+)_([\d_]+)/) # snare just the numeric part
431           if m{\$Name:\s*([^\$]+)\$}s
432          ;
433          $version = $_;
434          DEBUG and print "Noting $version as version\n";
435          last;
436        }
437      }
438      close(INPOD);
439    }
440    print "$name\t$version\t$file\n";
441    return;
442    # End of callback!
443  });
444
445  $self->survey;
446}
447
448#==========================================================================
449
450sub simplify_name {
451  my($self, $str) = @_;
452
453  # Remove all path components
454  #                             XXX Why not just use basename()? -- SMB
455
456  if ($^O eq 'MacOS') { $str =~ s{^.*:+}{}s }
457  else                { $str =~ s{^.*/+}{}s }
458
459  $self->_simplify_base($str);
460  return $str;
461}
462
463#==========================================================================
464
465sub _simplify_base {   # Internal method only
466
467  # strip Perl's own extensions
468  $_[1] =~ s/\.(pod|pm|plx?)\z//i;
469
470  # strip meaningless extensions on Win32 and OS/2
471  $_[1] =~ s/\.(bat|exe|cmd)\z//i if $^O =~ /mswin|os2/i;
472
473  # strip meaningless extensions on VMS
474  $_[1] =~ s/\.(com)\z//i if $^O eq 'VMS';
475
476  return;
477}
478
479#==========================================================================
480
481sub _expand_inc {
482  my($self, $search_dirs) = @_;
483
484  return unless $self->{'inc'};
485  my %seen = map { File::Spec->rel2abs($_) => 1 } @{ $search_dirs };
486
487  if ($^O eq 'MacOS') {
488    push @$search_dirs,
489      grep { !$seen{ File::Spec->rel2abs($_) }++ } $self->_mac_whammy(@INC);
490  # Any other OSs need custom handling here?
491  } else {
492    push @$search_dirs,
493      grep { !$seen{ File::Spec->rel2abs($_) }++ } @INC;
494  }
495
496  $self->{'laborious'} = 0;   # Since inc said to use INC
497  return;
498}
499
500#==========================================================================
501
502sub _mac_whammy { # Tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
503  my @them;
504  (undef,@them) = @_;
505  for $_ (@them) {
506    if ( $_ eq '.' ) {
507      $_ = ':';
508    } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
509      $_ = ':'. $_;
510    } else {
511      $_ =~ s|^\./|:|;
512    }
513  }
514  return @them;
515}
516
517#==========================================================================
518
519sub _limit_glob_to_limit_re {
520  my $self = $_[0];
521  my $limit_glob = $self->{'limit_glob'} || return;
522
523  my $limit_re = '^' . quotemeta($limit_glob) . '$';
524  $limit_re =~ s/\\\?/./g;    # glob "?" => "."
525  $limit_re =~ s/\\\*/.*?/g;  # glob "*" => ".*?"
526  $limit_re =~ s/\.\*\?\$$//s; # final glob "*" => ".*?$" => ""
527
528  $self->{'verbose'} and print "Turning limit_glob $limit_glob into re $limit_re\n";
529
530  # A common optimization:
531  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    $self->{'dir_prefix'} = join "::", $limit_glob =~ m/^(?:\w+::)+/sg;
536    $self->{'verbose'} and print " and setting dir_prefix to $self->{'dir_prefix'}\n";
537  }
538
539  return $limit_re;
540}
541
542#==========================================================================
543
544# contribution mostly from Tim Jenness <t.jenness@jach.hawaii.edu>
545
546sub _actual_filenames {
547    my $dir = shift;
548    my $fn = lc shift;
549    opendir my $dh, $dir or return;
550    return map { File::Spec->catdir($dir, $_) }
551        grep { lc $_  eq $fn } readdir $dh;
552}
553
554sub find {
555  my($self, $pod, @search_dirs) = @_;
556  $self = $self->new unless ref $self; # tolerate being a class method
557
558  # Check usage
559  Carp::carp 'Usage: \$self->find($podname, ...)'
560   unless defined $pod and length $pod;
561
562  my $verbose = $self->verbose;
563
564  # Split on :: and then join the name together using File::Spec
565  my @parts = split /::/, $pod;
566  $verbose and print "Chomping {$pod} => {@parts}\n";
567
568  #@search_dirs = File::Spec->curdir unless @search_dirs;
569
570  $self->_expand_inc(\@search_dirs);
571  # Add location of binaries such as pod2text:
572  push @search_dirs, $Config::Config{'scriptdir'} if $self->inc;
573
574  my %seen_dir;
575  while (my $dir = shift @search_dirs ) {
576    next unless defined $dir and length $dir;
577    next if $seen_dir{$dir};
578    $seen_dir{$dir} = 1;
579    unless(-d $dir) {
580      print "Directory $dir does not exist\n" if $verbose;
581    }
582
583    print "Looking in directory $dir\n" if $verbose;
584    my $fullname = File::Spec->catfile( $dir, @parts );
585    print "Filename is now $fullname\n" if $verbose;
586
587    foreach my $ext ('', '.pod', '.pm', '.pl') {   # possible extensions
588      my $fullext = $fullname . $ext;
589      if ( -f $fullext and $self->contains_pod($fullext) ) {
590        print "FOUND: $fullext\n" if $verbose;
591        if (@parts > 1 && lc $parts[0] eq 'pod' && $IS_CASE_INSENSITIVE && $ext eq '.pod') {
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          my $subdir = dirname $fullext;
596          unless (grep { $fullext eq $_  } _actual_filenames $subdir, "$parts[-1].pod") {
597            print "# Looking for alternate spelling in $subdir\n" if $verbose;
598            # Try the .pm file.
599            my $pm = $fullname . '.pm';
600            if ( -f $pm and $self->contains_pod($pm) ) {
601              # Prefer the .pm if its case matches.
602              if (grep { $pm eq $_  } _actual_filenames $subdir, "$parts[-1].pm") {
603                print "FOUND: $fullext\n" if $verbose;
604                return $pm;
605              }
606            }
607          }
608        }
609        return $fullext;
610      }
611    }
612
613    # Case-insensitively Look for ./pod directories and slip them in.
614    for my $subdir ( _actual_filenames($dir, 'pod') ) {
615      if (-d $subdir) {
616        $verbose and print "Noticing $subdir and looking there...\n";
617        unshift @search_dirs, $subdir;
618      }
619    }
620  }
621
622  return undef;
623}
624
625#==========================================================================
626
627sub contains_pod {
628  my($self, $file) = @_;
629  my $verbose = $self->{'verbose'};
630
631  # check for one line of POD
632  $verbose > 1 and print " Scanning $file for pod...\n";
633  unless( open(MAYBEPOD,"<$file") ) {
634    print "Error: $file is unreadable: $!\n";
635    return undef;
636  }
637
638  sleep($SLEEPY - 1) if $SLEEPY;
639   # avoid totally hogging the processor on OSs with poor process control
640
641  local $_;
642  while( <MAYBEPOD> ) {
643    if(m/^=(head\d|pod|over|item)\b/s) {
644      close(MAYBEPOD) || die "Bizarre error closing $file: $!\nAborting";
645      chomp;
646      $verbose > 1 and print "  Found some pod ($_) in $file\n";
647      return 1;
648    }
649  }
650  close(MAYBEPOD) || die "Bizarre error closing $file: $!\nAborting";
651  $verbose > 1 and print "  No POD in $file, skipping.\n";
652  return 0;
653}
654
655#==========================================================================
656
657sub _accessorize {  # A simple-minded method-maker
658  shift;
659  no strict 'refs';
660  foreach my $attrname (@_) {
661    *{caller() . '::' . $attrname} = sub {
662      use strict;
663      $Carp::CarpLevel = 1,  Carp::croak(
664       "Accessor usage: \$obj->$attrname() or \$obj->$attrname(\$new_value)"
665      ) unless (@_ == 1 or @_ == 2) and ref $_[0];
666
667      # Read access:
668      return $_[0]->{$attrname} if @_ == 1;
669
670      # Write access:
671      $_[0]->{$attrname} = $_[1];
672      return $_[0]; # RETURNS MYSELF!
673    };
674  }
675  # Ya know, they say accessories make the ensemble!
676  return;
677}
678
679#==========================================================================
680sub _state_as_string {
681  my $self = $_[0];
682  return '' unless ref $self;
683  my @out = "{\n  # State of $self ...\n";
684  foreach my $k (sort keys %$self) {
685    push @out, "  ", _esc($k), " => ", _esc($self->{$k}), ",\n";
686  }
687  push @out, "}\n";
688  my $x = join '', @out;
689  $x =~ s/^/#/mg;
690  return $x;
691}
692
693sub _esc {
694  my $in = $_[0];
695  return 'undef' unless defined $in;
696  $in =~
697    s<([^\x20\x21\x23\x27-\x3F\x41-\x5B\x5D-\x7E])>
698     <'\\x'.(unpack("H2",$1))>eg;
699  return qq{"$in"};
700}
701
702#==========================================================================
703
704run() unless caller;  # run if "perl whatever/Search.pm"
705
7061;
707
708#==========================================================================
709
710__END__
711
712
713=head1 NAME
714
715Pod::Simple::Search - find POD documents in directory trees
716
717=head1 SYNOPSIS
718
719  use Pod::Simple::Search;
720  my $name2path = Pod::Simple::Search->new->limit_glob('LWP::*')->survey;
721  print "Looky see what I found: ",
722    join(' ', sort keys %$name2path), "\n";
723
724  print "LWPUA docs = ",
725    Pod::Simple::Search->new->find('LWP::UserAgent') || "?",
726    "\n";
727
728=head1 DESCRIPTION
729
730B<Pod::Simple::Search> is a class that you use for running searches
731for Pod files.  An object of this class has several attributes
732(mostly options for controlling search options), and some methods
733for searching based on those attributes.
734
735The way to use this class is to make a new object of this class,
736set any options, and then call one of the search options
737(probably C<survey> or C<find>).  The sections below discuss the
738syntaxes for doing all that.
739
740
741=head1 CONSTRUCTOR
742
743This class provides the one constructor, called C<new>.
744It takes no parameters:
745
746  use Pod::Simple::Search;
747  my $search = Pod::Simple::Search->new;
748
749=head1 ACCESSORS
750
751This class defines several methods for setting (and, occasionally,
752reading) the contents of an object. With two exceptions (discussed at
753the end of this section), these attributes are just for controlling the
754way searches are carried out.
755
756Note that each of these return C<$self> when you call them as
757C<< $self->I<whatever(value)> >>.  That's so that you can chain
758together set-attribute calls like this:
759
760  my $name2path =
761    Pod::Simple::Search->new
762    -> inc(0) -> verbose(1) -> callback(\&blab)
763    ->survey(@there);
764
765...which works exactly as if you'd done this:
766
767  my $search = Pod::Simple::Search->new;
768  $search->inc(0);
769  $search->verbose(1);
770  $search->callback(\&blab);
771  my $name2path = $search->survey(@there);
772
773=over
774
775=item $search->inc( I<true-or-false> );
776
777This attribute, if set to a true value, means that searches should
778implicitly add perl's I<@INC> paths. This
779automatically considers paths specified in the C<PERL5LIB> environment
780as this is prepended to I<@INC> by the Perl interpreter itself.
781This attribute's default value is B<TRUE>.  If you want to search
782only specific directories, set $self->inc(0) before calling
783$inc->survey or $inc->find.
784
785
786=item $search->verbose( I<nonnegative-number> );
787
788This attribute, if set to a nonzero positive value, will make searches output
789(via C<warn>) notes about what they're doing as they do it.
790This option may be useful for debugging a pod-related module.
791This attribute's default value is zero, meaning that no C<warn> messages
792are produced.  (Setting verbose to 1 turns on some messages, and setting
793it to 2 turns on even more messages, i.e., makes the following search(es)
794even more verbose than 1 would make them.)
795
796=item $search->limit_glob( I<some-glob-string> );
797
798This option means that you want to limit the results just to items whose
799podnames match the given glob/wildcard expression. For example, you
800might limit your search to just "LWP::*", to search only for modules
801starting with "LWP::*" (but not including the module "LWP" itself); or
802you might limit your search to "LW*" to see only modules whose (full)
803names begin with "LW"; or you might search for "*Find*" to search for
804all modules with "Find" somewhere in their full name. (You can also use
805"?" in a glob expression; so "DB?" will match "DBI" and "DBD".)
806
807
808=item $search->callback( I<\&some_routine> );
809
810This attribute means that every time this search sees a matching
811Pod file, it should call this callback routine.  The routine is called
812with two parameters: the current file's filespec, and its pod name.
813(For example: C<("/etc/perljunk/File/Crunk.pm", "File::Crunk")> would
814be in C<@_>.)
815
816The callback routine's return value is not used for anything.
817
818This attribute's default value is false, meaning that no callback
819is called.
820
821=item $search->laborious( I<true-or-false> );
822
823Unless you set this attribute to a true value, Pod::Search will
824apply Perl-specific heuristics to find the correct module PODs quickly.
825This attribute's default value is false.  You won't normally need
826to set this to true.
827
828Specifically: Turning on this option will disable the heuristics for
829seeing only files with Perl-like extensions, omitting subdirectories
830that are numeric but do I<not> match the current Perl interpreter's
831version ID, suppressing F<site_perl> as a module hierarchy name, etc.
832
833=item $search->recurse( I<true-or-false> );
834
835Unless you set this attribute to a false value, Pod::Search will
836recurse into subdirectories of the search directories.
837
838=item $search->shadows( I<true-or-false> );
839
840Unless you set this attribute to a true value, Pod::Simple::Search will
841consider only the first file of a given modulename as it looks thru the
842specified directories; that is, with this option off, if
843Pod::Simple::Search has seen a C<somepathdir/Foo/Bar.pm> already in this
844search, then it won't bother looking at a C<somelaterpathdir/Foo/Bar.pm>
845later on in that search, because that file is merely a "shadow". But if
846you turn on C<< $self->shadows(1) >>, then these "shadow" files are
847inspected too, and are noted in the pathname2podname return hash.
848
849This attribute's default value is false; and normally you won't
850need to turn it on.
851
852
853=item $search->limit_re( I<some-regxp> );
854
855Setting this attribute (to a value that's a regexp) means that you want
856to limit the results just to items whose podnames match the given
857regexp. Normally this option is not needed, and the more efficient
858C<limit_glob> attribute is used instead.
859
860
861=item $search->dir_prefix( I<some-string-value> );
862
863Setting this attribute to a string value means that the searches should
864begin in the specified subdirectory name (like "Pod" or "File::Find",
865also expressible as "File/Find"). For example, the search option
866C<< $search->limit_glob("File::Find::R*") >>
867is the same as the combination of the search options
868C<< $search->limit_re("^File::Find::R") -> dir_prefix("File::Find") >>.
869
870Normally you don't need to know about the C<dir_prefix> option, but I
871include it in case it might prove useful for someone somewhere.
872
873(Implementationally, searching with limit_glob ends up setting limit_re
874and usually dir_prefix.)
875
876
877=item $search->progress( I<some-progress-object> );
878
879If you set a value for this attribute, the value is expected
880to be an object (probably of a class that you define) that has a
881C<reach> method and a C<done> method.  This is meant for reporting
882progress during the search, if you don't want to use a simple
883callback.
884
885Normally you don't need to know about the C<progress> option, but I
886include it in case it might prove useful for someone somewhere.
887
888While a search is in progress, the progress object's C<reach> and
889C<done> methods are called like this:
890
891  # Every time a file is being scanned for pod:
892  $progress->reach($count, "Scanning $file");   ++$count;
893
894  # And then at the end of the search:
895  $progress->done("Noted $count Pod files total");
896
897Internally, we often set this to an object of class
898Pod::Simple::Progress.  That class is probably undocumented,
899but you may wish to look at its source.
900
901
902=item $name2path = $self->name2path;
903
904This attribute is not a search parameter, but is used to report the
905result of C<survey> method, as discussed in the next section.
906
907=item $path2name = $self->path2name;
908
909This attribute is not a search parameter, but is used to report the
910result of C<survey> method, as discussed in the next section.
911
912=back
913
914=head1 MAIN SEARCH METHODS
915
916Once you've actually set any options you want (if any), you can go
917ahead and use the following methods to search for Pod files
918in particular ways.
919
920
921=head2 C<< $search->survey( @directories ) >>
922
923The method C<survey> searches for POD documents in a given set of
924files and/or directories.  This runs the search according to the various
925options set by the accessors above.  (For example, if the C<inc> attribute
926is on, as it is by default, then the perl @INC directories are implicitly
927added to the list of directories (if any) that you specify.)
928
929The return value of C<survey> is two hashes:
930
931=over
932
933=item C<name2path>
934
935A hash that maps from each pod-name to the filespec (like
936"Stuff::Thing" => "/whatever/plib/Stuff/Thing.pm")
937
938=item C<path2name>
939
940A hash that maps from each Pod filespec to its pod-name (like
941"/whatever/plib/Stuff/Thing.pm" => "Stuff::Thing")
942
943=back
944
945Besides saving these hashes as the hashref attributes
946C<name2path> and C<path2name>, calling this function also returns
947these hashrefs.  In list context, the return value of
948C<< $search->survey >> is the list C<(\%name2path, \%path2name)>.
949In scalar context, the return value is C<\%name2path>.
950Or you can just call this in void context.
951
952Regardless of calling context, calling C<survey> saves
953its results in its C<name2path> and C<path2name> attributes.
954
955E.g., when searching in F<$HOME/perl5lib>, the file
956F<$HOME/perl5lib/MyModule.pm> would get the POD name I<MyModule>,
957whereas F<$HOME/perl5lib/Myclass/Subclass.pm> would be
958I<Myclass::Subclass>. The name information can be used for POD
959translators.
960
961Only text files containing at least one valid POD command are found.
962
963In verbose mode, a warning is printed if shadows are found (i.e., more
964than one POD file with the same POD name is found, e.g. F<CPAN.pm> in
965different directories).  This usually indicates duplicate occurrences of
966modules in the I<@INC> search path, which is occasionally inadvertent
967(but is often simply a case of a user's path dir having a more recent
968version than the system's general path dirs in general.)
969
970The options to this argument is a list of either directories that are
971searched recursively, or files.  (Usually you wouldn't specify files,
972but just dirs.)  Or you can just specify an empty-list, as in
973$name2path; with the C<inc> option on, as it is by default.
974
975The POD names of files are the plain basenames with any Perl-like
976extension (.pm, .pl, .pod) stripped, and path separators replaced by
977C<::>'s.
978
979Calling Pod::Simple::Search->search(...) is short for
980Pod::Simple::Search->new->search(...).  That is, a throwaway object
981with default attribute values is used.
982
983
984=head2 C<< $search->simplify_name( $str ) >>
985
986The method B<simplify_name> is equivalent to B<basename>, but also
987strips Perl-like extensions (.pm, .pl, .pod) and extensions like
988F<.bat>, F<.cmd> on Win32 and OS/2, or F<.com> on VMS, respectively.
989
990
991=head2 C<< $search->find( $pod ) >>
992
993=head2 C<< $search->find( $pod, @search_dirs ) >>
994
995Returns the location of a Pod file, given a Pod/module/script name
996(like "Foo::Bar" or "perlvar" or "perldoc"), and an idea of
997what files/directories to look in.
998It searches according to the various options set by the accessors above.
999(For example, if the C<inc> attribute is on, as it is by default, then
1000the perl @INC directories are implicitly added to the list of
1001directories (if any) that you specify.)
1002
1003This returns the full path of the first occurrence to the file.
1004Package names (eg 'A::B') are automatically converted to directory
1005names in the selected directory.  Additionally, '.pm', '.pl' and '.pod'
1006are automatically appended to the search as required.
1007(So, for example, under Unix, "A::B" is converted to "somedir/A/B.pm",
1008"somedir/A/B.pod", or "somedir/A/B.pl", as appropriate.)
1009
1010If no such Pod file is found, this method returns undef.
1011
1012If any of the given search directories contains a F<pod/> subdirectory,
1013then it is searched.  (That's how we manage to find F<perlfunc>,
1014for example, which is usually in F<pod/perlfunc> in most Perl dists.)
1015
1016The C<verbose> and C<inc> attributes influence the behavior of this
1017search; notably, C<inc>, if true, adds @INC I<and also
1018$Config::Config{'scriptdir'}> to the list of directories to search.
1019
1020It is common to simply say C<< $filename = Pod::Simple::Search-> new
1021->find("perlvar") >> so that just the @INC (well, and scriptdir)
1022directories are searched.  (This happens because the C<inc>
1023attribute is true by default.)
1024
1025Calling Pod::Simple::Search->find(...) is short for
1026Pod::Simple::Search->new->find(...).  That is, a throwaway object
1027with default attribute values is used.
1028
1029
1030=head2 C<< $self->contains_pod( $file ) >>
1031
1032Returns true if the supplied filename (not POD module) contains some Pod
1033documentation.
1034
1035=head1 SUPPORT
1036
1037Questions or discussion about POD and Pod::Simple should be sent to the
1038pod-people@perl.org mail list. Send an empty email to
1039pod-people-subscribe@perl.org to subscribe.
1040
1041This module is managed in an open GitHub repository,
1042L<https://github.com/perl-pod/pod-simple/>. Feel free to fork and contribute, or
1043to clone L<git://github.com/perl-pod/pod-simple.git> and send patches!
1044
1045Patches against Pod::Simple are welcome. Please send bug reports to
1046<bug-pod-simple@rt.cpan.org>.
1047
1048=head1 COPYRIGHT AND DISCLAIMERS
1049
1050Copyright (c) 2002 Sean M. Burke.
1051
1052This library is free software; you can redistribute it and/or modify it
1053under the same terms as Perl itself.
1054
1055This program is distributed in the hope that it will be useful, but
1056without any warranty; without even the implied warranty of
1057merchantability or fitness for a particular purpose.
1058
1059=head1 AUTHOR
1060
1061Pod::Simple was created by Sean M. Burke <sburke@cpan.org> with code borrowed
1062from Marek Rouchal's L<Pod::Find>, which in turn heavily borrowed code from
1063Nick Ing-Simmons' C<PodToHtml>.
1064
1065But don't bother him, he's retired.
1066
1067Pod::Simple is maintained by:
1068
1069=over
1070
1071=item * Allison Randal C<allison@perl.org>
1072
1073=item * Hans Dieter Pearcey C<hdp@cpan.org>
1074
1075=item * David E. Wheeler C<dwheeler@cpan.org>
1076
1077=back
1078
1079=cut
1080