1 | #############################################################################
|
---|
2 | # Pod/Find.pm -- finds files containing POD documentation
|
---|
3 | #
|
---|
4 | # Author: Marek Rouchal <[email protected]>
|
---|
5 | #
|
---|
6 | # Copyright (C) 1999-2000 by Marek Rouchal (and borrowing code
|
---|
7 | # from Nick Ing-Simmon's PodToHtml). All rights reserved.
|
---|
8 | # This file is part of "PodParser". Pod::Find is free software;
|
---|
9 | # you can redistribute it and/or modify it under the same terms
|
---|
10 | # as Perl itself.
|
---|
11 | #############################################################################
|
---|
12 |
|
---|
13 | package Pod::Find;
|
---|
14 |
|
---|
15 | use vars qw($VERSION);
|
---|
16 | $VERSION = 1.34; ## Current version of this package
|
---|
17 | require 5.005; ## requires this Perl version or later
|
---|
18 | use Carp;
|
---|
19 |
|
---|
20 | #############################################################################
|
---|
21 |
|
---|
22 | =head1 NAME
|
---|
23 |
|
---|
24 | Pod::Find - find POD documents in directory trees
|
---|
25 |
|
---|
26 | =head1 SYNOPSIS
|
---|
27 |
|
---|
28 | use Pod::Find qw(pod_find simplify_name);
|
---|
29 | my %pods = pod_find({ -verbose => 1, -inc => 1 });
|
---|
30 | foreach(keys %pods) {
|
---|
31 | print "found library POD `$pods{$_}' in $_\n";
|
---|
32 | }
|
---|
33 |
|
---|
34 | print "podname=",simplify_name('a/b/c/mymodule.pod'),"\n";
|
---|
35 |
|
---|
36 | $location = pod_where( { -inc => 1 }, "Pod::Find" );
|
---|
37 |
|
---|
38 | =head1 DESCRIPTION
|
---|
39 |
|
---|
40 | B<Pod::Find> provides a set of functions to locate POD files. Note that
|
---|
41 | no function is exported by default to avoid pollution of your namespace,
|
---|
42 | so be sure to specify them in the B<use> statement if you need them:
|
---|
43 |
|
---|
44 | use Pod::Find qw(pod_find);
|
---|
45 |
|
---|
46 | From this version on the typical SCM (software configuration management)
|
---|
47 | files/directories like RCS, CVS, SCCS, .svn are ignored.
|
---|
48 |
|
---|
49 | =cut
|
---|
50 |
|
---|
51 | use strict;
|
---|
52 | #use diagnostics;
|
---|
53 | use Exporter;
|
---|
54 | use File::Spec;
|
---|
55 | use File::Find;
|
---|
56 | use Cwd;
|
---|
57 |
|
---|
58 | use vars qw(@ISA @EXPORT_OK $VERSION);
|
---|
59 | @ISA = qw(Exporter);
|
---|
60 | @EXPORT_OK = qw(&pod_find &simplify_name &pod_where &contains_pod);
|
---|
61 |
|
---|
62 | # package global variables
|
---|
63 | my $SIMPLIFY_RX;
|
---|
64 |
|
---|
65 | =head2 C<pod_find( { %opts } , @directories )>
|
---|
66 |
|
---|
67 | The function B<pod_find> searches for POD documents in a given set of
|
---|
68 | files and/or directories. It returns a hash with the file names as keys
|
---|
69 | and the POD name as value. The POD name is derived from the file name
|
---|
70 | and its position in the directory tree.
|
---|
71 |
|
---|
72 | E.g. when searching in F<$HOME/perl5lib>, the file
|
---|
73 | F<$HOME/perl5lib/MyModule.pm> would get the POD name I<MyModule>,
|
---|
74 | whereas F<$HOME/perl5lib/Myclass/Subclass.pm> would be
|
---|
75 | I<Myclass::Subclass>. The name information can be used for POD
|
---|
76 | translators.
|
---|
77 |
|
---|
78 | Only text files containing at least one valid POD command are found.
|
---|
79 |
|
---|
80 | A warning is printed if more than one POD file with the same POD name
|
---|
81 | is found, e.g. F<CPAN.pm> in different directories. This usually
|
---|
82 | indicates duplicate occurrences of modules in the I<@INC> search path.
|
---|
83 |
|
---|
84 | B<OPTIONS> The first argument for B<pod_find> may be a hash reference
|
---|
85 | with options. The rest are either directories that are searched
|
---|
86 | recursively or files. The POD names of files are the plain basenames
|
---|
87 | with any Perl-like extension (.pm, .pl, .pod) stripped.
|
---|
88 |
|
---|
89 | =over 4
|
---|
90 |
|
---|
91 | =item C<-verbose =E<gt> 1>
|
---|
92 |
|
---|
93 | Print progress information while scanning.
|
---|
94 |
|
---|
95 | =item C<-perl =E<gt> 1>
|
---|
96 |
|
---|
97 | Apply Perl-specific heuristics to find the correct PODs. This includes
|
---|
98 | stripping Perl-like extensions, omitting subdirectories that are numeric
|
---|
99 | but do I<not> match the current Perl interpreter's version id, suppressing
|
---|
100 | F<site_perl> as a module hierarchy name etc.
|
---|
101 |
|
---|
102 | =item C<-script =E<gt> 1>
|
---|
103 |
|
---|
104 | Search for PODs in the current Perl interpreter's installation
|
---|
105 | B<scriptdir>. This is taken from the local L<Config|Config> module.
|
---|
106 |
|
---|
107 | =item C<-inc =E<gt> 1>
|
---|
108 |
|
---|
109 | Search for PODs in the current Perl interpreter's I<@INC> paths. This
|
---|
110 | automatically considers paths specified in the C<PERL5LIB> environment
|
---|
111 | as this is prepended to I<@INC> by the Perl interpreter itself.
|
---|
112 |
|
---|
113 | =back
|
---|
114 |
|
---|
115 | =cut
|
---|
116 |
|
---|
117 | # return a hash of the POD files found
|
---|
118 | # first argument may be a hashref (options),
|
---|
119 | # rest is a list of directories to search recursively
|
---|
120 | sub pod_find
|
---|
121 | {
|
---|
122 | my %opts;
|
---|
123 | if(ref $_[0]) {
|
---|
124 | %opts = %{shift()};
|
---|
125 | }
|
---|
126 |
|
---|
127 | $opts{-verbose} ||= 0;
|
---|
128 | $opts{-perl} ||= 0;
|
---|
129 |
|
---|
130 | my (@search) = @_;
|
---|
131 |
|
---|
132 | if($opts{-script}) {
|
---|
133 | require Config;
|
---|
134 | push(@search, $Config::Config{scriptdir})
|
---|
135 | if -d $Config::Config{scriptdir};
|
---|
136 | $opts{-perl} = 1;
|
---|
137 | }
|
---|
138 |
|
---|
139 | if($opts{-inc}) {
|
---|
140 | if ($^O eq 'MacOS') {
|
---|
141 | # tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
|
---|
142 | my @new_INC = @INC;
|
---|
143 | for (@new_INC) {
|
---|
144 | if ( $_ eq '.' ) {
|
---|
145 | $_ = ':';
|
---|
146 | } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
|
---|
147 | $_ = ':'. $_;
|
---|
148 | } else {
|
---|
149 | $_ =~ s|^\./|:|;
|
---|
150 | }
|
---|
151 | }
|
---|
152 | push(@search, grep($_ ne File::Spec->curdir, @new_INC));
|
---|
153 | } else {
|
---|
154 | push(@search, grep($_ ne File::Spec->curdir, @INC));
|
---|
155 | }
|
---|
156 |
|
---|
157 | $opts{-perl} = 1;
|
---|
158 | }
|
---|
159 |
|
---|
160 | if($opts{-perl}) {
|
---|
161 | require Config;
|
---|
162 | # this code simplifies the POD name for Perl modules:
|
---|
163 | # * remove "site_perl"
|
---|
164 | # * remove e.g. "i586-linux" (from 'archname')
|
---|
165 | # * remove e.g. 5.00503
|
---|
166 | # * remove pod/ if followed by *.pod (e.g. in pod/perlfunc.pod)
|
---|
167 |
|
---|
168 | # Mac OS:
|
---|
169 | # * remove ":?site_perl:"
|
---|
170 | # * remove :?pod: if followed by *.pod (e.g. in :pod:perlfunc.pod)
|
---|
171 |
|
---|
172 | if ($^O eq 'MacOS') {
|
---|
173 | $SIMPLIFY_RX =
|
---|
174 | qq!^(?i:\:?site_perl\:|\:?pod\:(?=.*?\\.pod\\z))*!;
|
---|
175 | } else {
|
---|
176 | $SIMPLIFY_RX =
|
---|
177 | qq!^(?i:site(_perl)?/|\Q$Config::Config{archname}\E/|\\d+\\.\\d+([_.]?\\d+)?/|pod/(?=.*?\\.pod\\z))*!;
|
---|
178 | }
|
---|
179 | }
|
---|
180 |
|
---|
181 | my %dirs_visited;
|
---|
182 | my %pods;
|
---|
183 | my %names;
|
---|
184 | my $pwd = cwd();
|
---|
185 |
|
---|
186 | foreach my $try (@search) {
|
---|
187 | unless(File::Spec->file_name_is_absolute($try)) {
|
---|
188 | # make path absolute
|
---|
189 | $try = File::Spec->catfile($pwd,$try);
|
---|
190 | }
|
---|
191 | # simplify path
|
---|
192 | # on VMS canonpath will vmsify:[the.path], but File::Find::find
|
---|
193 | # wants /unixy/paths
|
---|
194 | $try = File::Spec->canonpath($try) if ($^O ne 'VMS');
|
---|
195 | $try = VMS::Filespec::unixify($try) if ($^O eq 'VMS');
|
---|
196 | my $name;
|
---|
197 | if(-f $try) {
|
---|
198 | if($name = _check_and_extract_name($try, $opts{-verbose})) {
|
---|
199 | _check_for_duplicates($try, $name, \%names, \%pods);
|
---|
200 | }
|
---|
201 | next;
|
---|
202 | }
|
---|
203 | my $root_rx = $^O eq 'MacOS' ? qq!^\Q$try\E! : qq!^\Q$try\E/!;
|
---|
204 | File::Find::find( sub {
|
---|
205 | my $item = $File::Find::name;
|
---|
206 | if(-d) {
|
---|
207 | if($item =~ m{/(?:RCS|CVS|SCCS|\.svn)$}) {
|
---|
208 | $File::Find::prune = 1;
|
---|
209 | return;
|
---|
210 | }
|
---|
211 | elsif($dirs_visited{$item}) {
|
---|
212 | warn "Directory '$item' already seen, skipping.\n"
|
---|
213 | if($opts{-verbose});
|
---|
214 | $File::Find::prune = 1;
|
---|
215 | return;
|
---|
216 | }
|
---|
217 | else {
|
---|
218 | $dirs_visited{$item} = 1;
|
---|
219 | }
|
---|
220 | if($opts{-perl} && /^(\d+\.[\d_]+)\z/s && eval "$1" != $]) {
|
---|
221 | $File::Find::prune = 1;
|
---|
222 | warn "Perl $] version mismatch on $_, skipping.\n"
|
---|
223 | if($opts{-verbose});
|
---|
224 | }
|
---|
225 | return;
|
---|
226 | }
|
---|
227 | if($name = _check_and_extract_name($item, $opts{-verbose}, $root_rx)) {
|
---|
228 | _check_for_duplicates($item, $name, \%names, \%pods);
|
---|
229 | }
|
---|
230 | }, $try); # end of File::Find::find
|
---|
231 | }
|
---|
232 | chdir $pwd;
|
---|
233 | %pods;
|
---|
234 | }
|
---|
235 |
|
---|
236 | sub _check_for_duplicates {
|
---|
237 | my ($file, $name, $names_ref, $pods_ref) = @_;
|
---|
238 | if($$names_ref{$name}) {
|
---|
239 | warn "Duplicate POD found (shadowing?): $name ($file)\n";
|
---|
240 | warn " Already seen in ",
|
---|
241 | join(' ', grep($$pods_ref{$_} eq $name, keys %$pods_ref)),"\n";
|
---|
242 | }
|
---|
243 | else {
|
---|
244 | $$names_ref{$name} = 1;
|
---|
245 | }
|
---|
246 | $$pods_ref{$file} = $name;
|
---|
247 | }
|
---|
248 |
|
---|
249 | sub _check_and_extract_name {
|
---|
250 | my ($file, $verbose, $root_rx) = @_;
|
---|
251 |
|
---|
252 | # check extension or executable flag
|
---|
253 | # this involves testing the .bat extension on Win32!
|
---|
254 | unless(-f $file && -T $file && ($file =~ /\.(pod|pm|plx?)\z/i || -x $file )) {
|
---|
255 | return undef;
|
---|
256 | }
|
---|
257 |
|
---|
258 | return undef unless contains_pod($file,$verbose);
|
---|
259 |
|
---|
260 | # strip non-significant path components
|
---|
261 | # TODO what happens on e.g. Win32?
|
---|
262 | my $name = $file;
|
---|
263 | if(defined $root_rx) {
|
---|
264 | $name =~ s!$root_rx!!s;
|
---|
265 | $name =~ s!$SIMPLIFY_RX!!os if(defined $SIMPLIFY_RX);
|
---|
266 | }
|
---|
267 | else {
|
---|
268 | if ($^O eq 'MacOS') {
|
---|
269 | $name =~ s/^.*://s;
|
---|
270 | } else {
|
---|
271 | $name =~ s:^.*/::s;
|
---|
272 | }
|
---|
273 | }
|
---|
274 | _simplify($name);
|
---|
275 | $name =~ s!/+!::!g; #/
|
---|
276 | if ($^O eq 'MacOS') {
|
---|
277 | $name =~ s!:+!::!g; # : -> ::
|
---|
278 | } else {
|
---|
279 | $name =~ s!/+!::!g; # / -> ::
|
---|
280 | }
|
---|
281 | $name;
|
---|
282 | }
|
---|
283 |
|
---|
284 | =head2 C<simplify_name( $str )>
|
---|
285 |
|
---|
286 | The function B<simplify_name> is equivalent to B<basename>, but also
|
---|
287 | strips Perl-like extensions (.pm, .pl, .pod) and extensions like
|
---|
288 | F<.bat>, F<.cmd> on Win32 and OS/2, or F<.com> on VMS, respectively.
|
---|
289 |
|
---|
290 | =cut
|
---|
291 |
|
---|
292 | # basic simplification of the POD name:
|
---|
293 | # basename & strip extension
|
---|
294 | sub simplify_name {
|
---|
295 | my ($str) = @_;
|
---|
296 | # remove all path components
|
---|
297 | if ($^O eq 'MacOS') {
|
---|
298 | $str =~ s/^.*://s;
|
---|
299 | } else {
|
---|
300 | $str =~ s:^.*/::s;
|
---|
301 | }
|
---|
302 | _simplify($str);
|
---|
303 | $str;
|
---|
304 | }
|
---|
305 |
|
---|
306 | # internal sub only
|
---|
307 | sub _simplify {
|
---|
308 | # strip Perl's own extensions
|
---|
309 | $_[0] =~ s/\.(pod|pm|plx?)\z//i;
|
---|
310 | # strip meaningless extensions on Win32 and OS/2
|
---|
311 | $_[0] =~ s/\.(bat|exe|cmd)\z//i if($^O =~ /mswin|os2/i);
|
---|
312 | # strip meaningless extensions on VMS
|
---|
313 | $_[0] =~ s/\.(com)\z//i if($^O eq 'VMS');
|
---|
314 | }
|
---|
315 |
|
---|
316 | # contribution from Tim Jenness <[email protected]>
|
---|
317 |
|
---|
318 | =head2 C<pod_where( { %opts }, $pod )>
|
---|
319 |
|
---|
320 | Returns the location of a pod document given a search directory
|
---|
321 | and a module (e.g. C<File::Find>) or script (e.g. C<perldoc>) name.
|
---|
322 |
|
---|
323 | Options:
|
---|
324 |
|
---|
325 | =over 4
|
---|
326 |
|
---|
327 | =item C<-inc =E<gt> 1>
|
---|
328 |
|
---|
329 | Search @INC for the pod and also the C<scriptdir> defined in the
|
---|
330 | L<Config|Config> module.
|
---|
331 |
|
---|
332 | =item C<-dirs =E<gt> [ $dir1, $dir2, ... ]>
|
---|
333 |
|
---|
334 | Reference to an array of search directories. These are searched in order
|
---|
335 | before looking in C<@INC> (if B<-inc>). Current directory is used if
|
---|
336 | none are specified.
|
---|
337 |
|
---|
338 | =item C<-verbose =E<gt> 1>
|
---|
339 |
|
---|
340 | List directories as they are searched
|
---|
341 |
|
---|
342 | =back
|
---|
343 |
|
---|
344 | Returns the full path of the first occurrence to the file.
|
---|
345 | Package names (eg 'A::B') are automatically converted to directory
|
---|
346 | names in the selected directory. (eg on unix 'A::B' is converted to
|
---|
347 | 'A/B'). Additionally, '.pm', '.pl' and '.pod' are appended to the
|
---|
348 | search automatically if required.
|
---|
349 |
|
---|
350 | A subdirectory F<pod/> is also checked if it exists in any of the given
|
---|
351 | search directories. This ensures that e.g. L<perlfunc|perlfunc> is
|
---|
352 | found.
|
---|
353 |
|
---|
354 | It is assumed that if a module name is supplied, that that name
|
---|
355 | matches the file name. Pods are not opened to check for the 'NAME'
|
---|
356 | entry.
|
---|
357 |
|
---|
358 | A check is made to make sure that the file that is found does
|
---|
359 | contain some pod documentation.
|
---|
360 |
|
---|
361 | =cut
|
---|
362 |
|
---|
363 | sub pod_where {
|
---|
364 |
|
---|
365 | # default options
|
---|
366 | my %options = (
|
---|
367 | '-inc' => 0,
|
---|
368 | '-verbose' => 0,
|
---|
369 | '-dirs' => [ File::Spec->curdir ],
|
---|
370 | );
|
---|
371 |
|
---|
372 | # Check for an options hash as first argument
|
---|
373 | if (defined $_[0] && ref($_[0]) eq 'HASH') {
|
---|
374 | my $opt = shift;
|
---|
375 |
|
---|
376 | # Merge default options with supplied options
|
---|
377 | %options = (%options, %$opt);
|
---|
378 | }
|
---|
379 |
|
---|
380 | # Check usage
|
---|
381 | carp 'Usage: pod_where({options}, $pod)' unless (scalar(@_));
|
---|
382 |
|
---|
383 | # Read argument
|
---|
384 | my $pod = shift;
|
---|
385 |
|
---|
386 | # Split on :: and then join the name together using File::Spec
|
---|
387 | my @parts = split (/::/, $pod);
|
---|
388 |
|
---|
389 | # Get full directory list
|
---|
390 | my @search_dirs = @{ $options{'-dirs'} };
|
---|
391 |
|
---|
392 | if ($options{'-inc'}) {
|
---|
393 |
|
---|
394 | require Config;
|
---|
395 |
|
---|
396 | # Add @INC
|
---|
397 | if ($^O eq 'MacOS' && $options{'-inc'}) {
|
---|
398 | # tolerate '.', './some_dir' and '(../)+some_dir' on Mac OS
|
---|
399 | my @new_INC = @INC;
|
---|
400 | for (@new_INC) {
|
---|
401 | if ( $_ eq '.' ) {
|
---|
402 | $_ = ':';
|
---|
403 | } elsif ( $_ =~ s|^((?:\.\./)+)|':' x (length($1)/3)|e ) {
|
---|
404 | $_ = ':'. $_;
|
---|
405 | } else {
|
---|
406 | $_ =~ s|^\./|:|;
|
---|
407 | }
|
---|
408 | }
|
---|
409 | push (@search_dirs, @new_INC);
|
---|
410 | } elsif ($options{'-inc'}) {
|
---|
411 | push (@search_dirs, @INC);
|
---|
412 | }
|
---|
413 |
|
---|
414 | # Add location of pod documentation for perl man pages (eg perlfunc)
|
---|
415 | # This is a pod directory in the private install tree
|
---|
416 | #my $perlpoddir = File::Spec->catdir($Config::Config{'installprivlib'},
|
---|
417 | # 'pod');
|
---|
418 | #push (@search_dirs, $perlpoddir)
|
---|
419 | # if -d $perlpoddir;
|
---|
420 |
|
---|
421 | # Add location of binaries such as pod2text
|
---|
422 | push (@search_dirs, $Config::Config{'scriptdir'})
|
---|
423 | if -d $Config::Config{'scriptdir'};
|
---|
424 | }
|
---|
425 |
|
---|
426 | warn "Search path is: ".join(' ', @search_dirs)."\n"
|
---|
427 | if $options{'-verbose'};
|
---|
428 |
|
---|
429 | # Loop over directories
|
---|
430 | Dir: foreach my $dir ( @search_dirs ) {
|
---|
431 |
|
---|
432 | # Don't bother if can't find the directory
|
---|
433 | if (-d $dir) {
|
---|
434 | warn "Looking in directory $dir\n"
|
---|
435 | if $options{'-verbose'};
|
---|
436 |
|
---|
437 | # Now concatenate this directory with the pod we are searching for
|
---|
438 | my $fullname = File::Spec->catfile($dir, @parts);
|
---|
439 | warn "Filename is now $fullname\n"
|
---|
440 | if $options{'-verbose'};
|
---|
441 |
|
---|
442 | # Loop over possible extensions
|
---|
443 | foreach my $ext ('', '.pod', '.pm', '.pl') {
|
---|
444 | my $fullext = $fullname . $ext;
|
---|
445 | if (-f $fullext &&
|
---|
446 | contains_pod($fullext, $options{'-verbose'}) ) {
|
---|
447 | warn "FOUND: $fullext\n" if $options{'-verbose'};
|
---|
448 | return $fullext;
|
---|
449 | }
|
---|
450 | }
|
---|
451 | } else {
|
---|
452 | warn "Directory $dir does not exist\n"
|
---|
453 | if $options{'-verbose'};
|
---|
454 | next Dir;
|
---|
455 | }
|
---|
456 | # for some strange reason the path on MacOS/darwin/cygwin is
|
---|
457 | # 'pods' not 'pod'
|
---|
458 | # this could be the case also for other systems that
|
---|
459 | # have a case-tolerant file system, but File::Spec
|
---|
460 | # does not recognize 'darwin' yet. And cygwin also has "pods",
|
---|
461 | # but is not case tolerant. Oh well...
|
---|
462 | if((File::Spec->case_tolerant || $^O =~ /macos|darwin|cygwin/i)
|
---|
463 | && -d File::Spec->catdir($dir,'pods')) {
|
---|
464 | $dir = File::Spec->catdir($dir,'pods');
|
---|
465 | redo Dir;
|
---|
466 | }
|
---|
467 | if(-d File::Spec->catdir($dir,'pod')) {
|
---|
468 | $dir = File::Spec->catdir($dir,'pod');
|
---|
469 | redo Dir;
|
---|
470 | }
|
---|
471 | }
|
---|
472 | # No match;
|
---|
473 | return undef;
|
---|
474 | }
|
---|
475 |
|
---|
476 | =head2 C<contains_pod( $file , $verbose )>
|
---|
477 |
|
---|
478 | Returns true if the supplied filename (not POD module) contains some pod
|
---|
479 | information.
|
---|
480 |
|
---|
481 | =cut
|
---|
482 |
|
---|
483 | sub contains_pod {
|
---|
484 | my $file = shift;
|
---|
485 | my $verbose = 0;
|
---|
486 | $verbose = shift if @_;
|
---|
487 |
|
---|
488 | # check for one line of POD
|
---|
489 | unless(open(POD,"<$file")) {
|
---|
490 | warn "Error: $file is unreadable: $!\n";
|
---|
491 | return undef;
|
---|
492 | }
|
---|
493 |
|
---|
494 | local $/ = undef;
|
---|
495 | my $pod = <POD>;
|
---|
496 | close(POD) || die "Error closing $file: $!\n";
|
---|
497 | unless($pod =~ /^=(head\d|pod|over|item)\b/m) {
|
---|
498 | warn "No POD in $file, skipping.\n"
|
---|
499 | if($verbose);
|
---|
500 | return 0;
|
---|
501 | }
|
---|
502 |
|
---|
503 | return 1;
|
---|
504 | }
|
---|
505 |
|
---|
506 | =head1 AUTHOR
|
---|
507 |
|
---|
508 | Please report bugs using L<http://rt.cpan.org>.
|
---|
509 |
|
---|
510 | Marek Rouchal E<lt>[email protected]<gt>,
|
---|
511 | heavily borrowing code from Nick Ing-Simmons' PodToHtml.
|
---|
512 |
|
---|
513 | Tim Jenness E<lt>[email protected]<gt> provided
|
---|
514 | C<pod_where> and C<contains_pod>.
|
---|
515 |
|
---|
516 | =head1 SEE ALSO
|
---|
517 |
|
---|
518 | L<Pod::Parser>, L<Pod::Checker>, L<perldoc>
|
---|
519 |
|
---|
520 | =cut
|
---|
521 |
|
---|
522 | 1;
|
---|
523 |
|
---|