This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
document Git_Data
[perl5.git] / lib / Pod / Find.pm
index c1aaac4..8d1103b 100644 (file)
@@ -1,7 +1,7 @@
 #############################################################################  
 # Pod/Find.pm -- finds files containing POD documentation
 #
-# Author: Marek Rouchal <marek@saftsack.fs.uni-bayreuth.de>
+# Author: Marek Rouchal <marekr@cpan.org>
 # 
 # Copyright (C) 1999-2000 by Marek Rouchal (and borrowing code
 # from Nick Ing-Simmon's PodToHtml). All rights reserved.
 #############################################################################
 
 package Pod::Find;
+use strict;
 
 use vars qw($VERSION);
-$VERSION = 0.22;   ## Current version of this package
+$VERSION = '1.35';   ## Current version of this package
 require  5.005;   ## requires this Perl version or later
 use Carp;
 
+BEGIN {
+   if ($] < 5.006) {
+      require Symbol;
+      import Symbol;
+   }
+}
+
 #############################################################################
 
 =head1 NAME
@@ -43,9 +51,11 @@ so be sure to specify them in the B<use> statement if you need them:
 
   use Pod::Find qw(pod_find);
 
+From this version on the typical SCM (software configuration management)
+files/directories like RCS, CVS, SCCS, .svn are ignored.
+
 =cut
 
-use strict;
 #use diagnostics;
 use Exporter;
 use File::Spec;
@@ -105,7 +115,7 @@ B<scriptdir>. This is taken from the local L<Config|Config> module.
 
 Search for PODs in the current Perl interpreter's I<@INC> paths. This
 automatically considers paths specified in the C<PERL5LIB> environment
-as this is prepended to I<@INC> by the Perl interpreter itself.
+as this is included in I<@INC> by the Perl interpreter itself.
 
 =back
 
@@ -128,12 +138,29 @@ sub pod_find
 
     if($opts{-script}) {
         require Config;
-        push(@search, $Config::Config{scriptdir});
+        push(@search, $Config::Config{scriptdir})
+            if -d $Config::Config{scriptdir};
         $opts{-perl} = 1;
     }
 
     if($opts{-inc}) {
-        push(@search, grep($_ ne '.',@INC));
+        if ($^O eq 'MacOS') {
+            # tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
+            my @new_INC = @INC;
+            for (@new_INC) {
+                if ( $_ eq '.' ) {
+                    $_ = ':';
+                } elsif ( $_ =~ s{^((?:\.\./)+)}{':' x (length($1)/3)}e ) {
+                    $_ = ':'. $_;
+                } else {
+                    $_ =~ s{^\./}{:};
+                }
+            }
+            push(@search, grep($_ ne File::Spec->curdir, @new_INC));
+        } else {
+            push(@search, grep($_ ne File::Spec->curdir, @INC));
+        }
+
         $opts{-perl} = 1;
     }
 
@@ -144,9 +171,18 @@ sub pod_find
         # * remove e.g. "i586-linux" (from 'archname')
         # * remove e.g. 5.00503
         # * remove pod/ if followed by *.pod (e.g. in pod/perlfunc.pod)
-        $SIMPLIFY_RX =
-          qq!^(?i:site(_perl)?/|\Q$Config::Config{archname}\E/|\\d+\\.\\d+([_.]?\\d+)?/|pod/(?=.*?\\.pod\\z))*!;
 
+        # Mac OS:
+        # * remove ":?site_perl:"
+        # * remove :?pod: if followed by *.pod (e.g. in :pod:perlfunc.pod)
+
+        if ($^O eq 'MacOS') {
+            $SIMPLIFY_RX =
+              qq!^(?i:\:?site_perl\:|\:?pod\:(?=.*?\\.pod\\z))*!;
+        } else {
+            $SIMPLIFY_RX =
+              qq!^(?i:site(_perl)?/|\Q$Config::Config{archname}\E/|\\d+\\.\\d+([_.]?\\d+)?/|pod/(?=.*?\\.pod\\z))*!;
+        }
     }
 
     my %dirs_visited;
@@ -171,11 +207,15 @@ sub pod_find
             }
             next;
         }
-        my $root_rx = qq!^\Q$try\E/!;
+        my $root_rx = $^O eq 'MacOS' ? qq!^\Q$try\E! : qq!^\Q$try\E/!;
         File::Find::find( sub {
             my $item = $File::Find::name;
             if(-d) {
-                if($dirs_visited{$item}) {
+                if($item =~ m{/(?:RCS|CVS|SCCS|\.svn)$}) {
+                    $File::Find::prune = 1;
+                    return;
+                }
+                elsif($dirs_visited{$item}) {
                     warn "Directory '$item' already seen, skipping.\n"
                         if($opts{-verbose});
                     $File::Find::prune = 1;
@@ -197,20 +237,20 @@ sub pod_find
         }, $try); # end of File::Find::find
     }
     chdir $pwd;
-    %pods;
+    return %pods;
 }
 
 sub _check_for_duplicates {
     my ($file, $name, $names_ref, $pods_ref) = @_;
     if($$names_ref{$name}) {
         warn "Duplicate POD found (shadowing?): $name ($file)\n";
-        warn "    Already seen in ",
+        warn '    Already seen in ',
             join(' ', grep($$pods_ref{$_} eq $name, keys %$pods_ref)),"\n";
     }
     else {
         $$names_ref{$name} = 1;
     }
-    $$pods_ref{$file} = $name;
+    return $$pods_ref{$file} = $name;
 }
 
 sub _check_and_extract_name {
@@ -218,25 +258,34 @@ sub _check_and_extract_name {
 
     # check extension or executable flag
     # this involves testing the .bat extension on Win32!
-    unless(-f $file && -T _ && ($file =~ /\.(pod|pm|plx?)\z/i || -x _ )) {
-      return undef;
+    unless(-f $file && -T $file && ($file =~ /\.(pod|pm|plx?)\z/i || -x $file )) {
+      return;
     }
 
-    return undef unless contains_pod($file,$verbose);
+    return unless contains_pod($file,$verbose);
 
     # strip non-significant path components
     # TODO what happens on e.g. Win32?
     my $name = $file;
     if(defined $root_rx) {
-        $name =~ s!$root_rx!!s;
-        $name =~ s!$SIMPLIFY_RX!!os if(defined $SIMPLIFY_RX);
+        $name =~ s/$root_rx//s;
+        $name =~ s/$SIMPLIFY_RX//s if(defined $SIMPLIFY_RX);
     }
     else {
-        $name =~ s:^.*/::s;
+        if ($^O eq 'MacOS') {
+            $name =~ s/^.*://s;
+        } else {
+            $name =~ s{^.*/}{}s;
+        }
     }
     _simplify($name);
-    $name =~ s!/+!::!g; #/
-    $name;
+    $name =~ s{/+}{::}g;
+    if ($^O eq 'MacOS') {
+        $name =~ s{:+}{::}g; # : -> ::
+    } else {
+        $name =~ s{/+}{::}g; # / -> ::
+    }
+    return $name;
 }
 
 =head2 C<simplify_name( $str )>
@@ -252,9 +301,13 @@ F<.bat>, F<.cmd> on Win32 and OS/2, or F<.com> on VMS, respectively.
 sub simplify_name {
     my ($str) = @_;
     # remove all path components
-    $str =~ s:^.*/::s;
+    if ($^O eq 'MacOS') {
+        $str =~ s/^.*://s;
+    } else {
+        $str =~ s{^.*/}{}s;
+    }
     _simplify($str);
-    $str;
+    return $str;
 }
 
 # internal sub only
@@ -295,7 +348,7 @@ List directories as they are searched
 
 =back
 
-Returns the full path of the first occurence to the file.
+Returns the full path of the first occurrence to the file.
 Package names (eg 'A::B') are automatically converted to directory
 names in the selected directory. (eg on unix 'A::B' is converted to
 'A/B'). Additionally, '.pm', '.pl' and '.pod' are appended to the
@@ -320,7 +373,7 @@ sub pod_where {
   my %options = (
          '-inc' => 0,
          '-verbose' => 0,
-         '-dirs' => [ '.' ],
+         '-dirs' => [ File::Spec->curdir ],
         );
 
   # Check for an options hash as first argument
@@ -348,7 +401,22 @@ sub pod_where {
     require Config;
 
     # Add @INC
-    push (@search_dirs, @INC) if $options{'-inc'};
+    if ($^O eq 'MacOS' && $options{'-inc'}) {
+        # tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
+        my @new_INC = @INC;
+        for (@new_INC) {
+            if ( $_ eq '.' ) {
+                $_ = ':';
+            } elsif ( $_ =~ s{^((?:\.\./)+)}{':' x (length($1)/3)}e ) {
+                $_ = ':'. $_;
+            } else {
+                $_ =~ s{^\./}{:};
+            }
+        }
+        push (@search_dirs, @new_INC);
+    } elsif ($options{'-inc'}) {
+        push (@search_dirs, @INC);
+    }
 
     # Add location of pod documentation for perl man pages (eg perlfunc)
     # This is a pod directory in the private install tree
@@ -362,12 +430,15 @@ sub pod_where {
       if -d $Config::Config{'scriptdir'};
   }
 
+  warn 'Search path is: '.join(' ', @search_dirs)."\n"
+        if $options{'-verbose'};
+
   # Loop over directories
   Dir: foreach my $dir ( @search_dirs ) {
 
-    # Don't bother if cant find the directory
+    # Don't bother if can't find the directory
     if (-d $dir) {
-      warn "Looking in directory $dir\n" 
+      warn "Looking in directory $dir\n"
         if $options{'-verbose'};
 
       # Now concatenate this directory with the pod we are searching for
@@ -378,7 +449,7 @@ sub pod_where {
       # Loop over possible extensions
       foreach my $ext ('', '.pod', '.pm', '.pl') {
         my $fullext = $fullname . $ext;
-        if (-f $fullext && 
+        if (-f $fullext &&
          contains_pod($fullext, $options{'-verbose'}) ) {
           warn "FOUND: $fullext\n" if $options{'-verbose'};
           return $fullext;
@@ -389,13 +460,24 @@ sub pod_where {
         if $options{'-verbose'};
       next Dir;
     }
+    # for some strange reason the path on MacOS/darwin/cygwin is
+    # 'pods' not 'pod'
+    # this could be the case also for other systems that
+    # have a case-tolerant file system, but File::Spec
+    # does not recognize 'darwin' yet. And cygwin also has "pods",
+    # but is not case tolerant. Oh well...
+    if((File::Spec->case_tolerant || $^O =~ /macos|darwin|cygwin/i)
+     && -d File::Spec->catdir($dir,'pods')) {
+      $dir = File::Spec->catdir($dir,'pods');
+      redo Dir;
+    }
     if(-d File::Spec->catdir($dir,'pod')) {
       $dir = File::Spec->catdir($dir,'pod');
       redo Dir;
     }
   }
   # No match;
-  return undef;
+  return;
 }
 
 =head2 C<contains_pod( $file , $verbose )>
@@ -411,15 +493,20 @@ sub contains_pod {
   $verbose = shift if @_;
 
   # check for one line of POD
-  unless(open(POD,"<$file")) {
+  my $podfh;
+  if ($] < 5.006) {
+    $podfh = gensym();
+  }
+
+  unless(open($podfh,"<$file")) {
     warn "Error: $file is unreadable: $!\n";
-    return undef;
+    return;
   }
   
   local $/ = undef;
-  my $pod = <POD>;
-  close(POD) || die "Error closing $file: $!\n";
-  unless($pod =~ /\n=(head\d|pod|over|item)\b/s) {
+  my $pod = <$podfh>;
+  close($podfh) || die "Error closing $file: $!\n";
+  unless($pod =~ /^=(head\d|pod|over|item|cut)\b/m) {
     warn "No POD in $file, skipping.\n"
       if($verbose);
     return 0;
@@ -430,7 +517,9 @@ sub contains_pod {
 
 =head1 AUTHOR
 
-Marek Rouchal E<lt>marek@saftsack.fs.uni-bayreuth.deE<gt>,
+Please report bugs using L<http://rt.cpan.org>.
+
+Marek Rouchal E<lt>marekr@cpan.orgE<gt>,
 heavily borrowing code from Nick Ing-Simmons' PodToHtml.
 
 Tim Jenness E<lt>t.jenness@jach.hawaii.eduE<gt> provided