perldoc -m
[p5sagit/p5-mst-13.2.git] / utils / perldoc.PL
1 #!/usr/local/bin/perl
2
3 use Config;
4 use File::Basename qw(&basename &dirname);
5
6 # List explicitly here the variables you want Configure to
7 # generate.  Metaconfig only looks for shell variables, so you
8 # have to mention them as if they were shell variables, not
9 # %Config entries.  Thus you write
10 #  $startperl
11 # to ensure Configure will look for $Config{startperl}.
12
13 # This forces PL files to create target in same directory as PL file.
14 # This is so that make depend always knows where to find PL derivatives.
15 chdir dirname($0);
16 $file = basename($0, '.PL');
17 $file .= '.com' if $^O eq 'VMS';
18
19 open OUT,">$file" or die "Can't create $file: $!";
20
21 print "Extracting $file (with variable substitutions)\n";
22
23 # In this section, perl variables will be expanded during extraction.
24 # You can use $Config{...} to use Configure variables.
25
26 print OUT <<"!GROK!THIS!";
27 $Config{startperl}
28     eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
29         if \$running_under_some_shell;
30
31 \@pagers = ();
32 push \@pagers, "$Config{'pager'}" if -x "$Config{'pager'}";
33 !GROK!THIS!
34
35 # In the following, perl variables are not expanded during extraction.
36
37 print OUT <<'!NO!SUBS!';
38
39 #
40 # Perldoc revision #1 -- look up a piece of documentation in .pod format that
41 # is embedded in the perl installation tree.
42 #
43 # This is not to be confused with Tom Christianson's perlman, which is a
44 # man replacement, written in perl. This perldoc is strictly for reading
45 # the perl manuals, though it too is written in perl.
46
47 if(@ARGV<1) {
48         $me = $0;               # Editing $0 is unportable
49         $me =~ s,.*/,,;
50         die <<EOF;
51 Usage: $me [-h] [-v] [-t] [-u] [-m] [-l] [-F] [-X] PageName|ModuleName|ProgramName
52        $me -f PerlFunc
53
54 The -h option prints more help.  Also try "perldoc perldoc" to get
55 aquainted with the system.
56 EOF
57 }
58
59 use Getopt::Std;
60 use Config '%Config';
61
62 @global_found = ();
63 $global_target = "";
64
65 $Is_VMS = $^O eq 'VMS';
66 $Is_MSWin32 = $^O eq 'MSWin32';
67 $Is_Dos = $^O eq 'dos';
68
69 sub usage{
70     warn "@_\n" if @_;
71     # Erase evidence of previous errors (if any), so exit status is simple.
72     $! = 0;
73     die <<EOF;
74 perldoc [options] PageName|ModuleName|ProgramName...
75 perldoc [options] -f BuiltinFunction
76
77 Options:
78     -h   Display this help message
79     -t   Display pod using pod2text instead of pod2man and nroff
80              (-t is the default on win32)
81     -u   Display unformatted pod text
82     -m   Display modules file in its entirety
83     -l   Display the modules file name
84     -F   Arguments are file names, not modules
85     -v   Verbosely describe what's going on
86     -X   use index if present (looks for pod.idx at $Config{archlib})
87
88 PageName|ModuleName...
89          is the name of a piece of documentation that you want to look at. You 
90          may either give a descriptive name of the page (as in the case of
91          `perlfunc') the name of a module, either like `Term::Info', 
92          `Term/Info', the partial name of a module, like `info', or 
93          `makemaker', or the name of a program, like `perldoc'.
94
95 BuiltinFunction
96          is the name of a perl function.  Will extract documentation from
97          `perlfunc'.
98          
99 Any switches in the PERLDOC environment variable will be used before the 
100 command line arguments.  The optional pod index file contains a list of
101 filenames, one per line.
102
103 EOF
104 }
105
106 use Text::ParseWords;
107
108
109 unshift(@ARGV,shellwords($ENV{"PERLDOC"}));
110
111 getopts("mhtluvFf:X") || usage;
112
113 usage if $opt_h || $opt_h; # avoid -w warning
114
115 $podidx = "$Config{'archlib'}/pod.idx";
116 $podidx = "" if $opt_X || !-f "pod.idx" && !-r _ && -M _ > 7;
117
118 if ($opt_t + $opt_u + $opt_m + $opt_l > 1) {
119     usage("only one of -t, -u, -m or -l")
120 } elsif ($Is_MSWin32 || $Is_Dos) {
121     $opt_t = 1 unless $opt_t + $opt_u + $opt_m + $opt_l;
122 }
123
124 if ($opt_t) { require Pod::Text; import Pod::Text; }
125
126 if ($opt_f) {
127    @pages = ("perlfunc");
128 } else {
129    @pages = @ARGV;
130 }
131
132 # Does this look like a module or extension directory?
133 if (-f "Makefile.PL") {
134         # Add ., lib and blib/* libs to @INC (if they exist)
135         unshift(@INC, '.');
136         unshift(@INC, 'lib') if -d 'lib';
137         require ExtUtils::testlib;
138 }
139
140
141
142 sub containspod {
143     my($file, $readit) = @_;
144     return 1 if !$readit && $file =~ /\.pod$/i;
145     local($_);
146     open(TEST,"<$file");
147     while(<TEST>) {
148         if(/^=head/) {
149             close(TEST);
150             return 1;
151         }
152     }
153     close(TEST);
154     return 0;
155 }
156
157 sub minus_f_nocase {
158      my($file) = @_;
159      # on a case-forgiving file system we can simply use -f $file
160      if ($Is_VMS or $Is_MSWin32 or $Is_Dos or $^O eq 'os2') {
161         return $file if -f $file and -r _;
162         warn "Ignored $file: unreadable\n" if -f _;
163         return '';
164      }
165      local *DIR;
166      local($")="/";
167      my(@p,$p,$cip);
168      foreach $p (split(/\//, $file)){
169         my $try = "@p/$p";
170         stat $try;
171         if (-d _){
172             push @p, $p;
173             if ( $p eq $global_target) {
174                 $tmp_path = join ('/', @p);
175                 my $path_f = 0;
176                 for (@global_found) {
177                     $path_f = 1 if $_ eq $tmp_path;
178                 }
179                 push (@global_found, $tmp_path) unless $path_f;
180                 print STDERR "Found as @p but directory\n" if $opt_v;
181             }
182         } elsif (-f _ && -r _) {
183             return $try;
184         } elsif (-f _) {
185             warn "Ignored $try: unreadable\n";
186         } else {
187             my $found=0;
188             my $lcp = lc $p;
189             opendir DIR, "@p";
190             while ($cip=readdir(DIR)) {
191                 if (lc $cip eq $lcp){
192                     $found++;
193                     last;
194                 }
195             }
196             closedir DIR;
197             return "" unless $found;
198             push @p, $cip;
199             return "@p" if -f "@p" and -r _;
200             warn "Ignored $file: unreadable\n" if -f _;
201         }
202      }
203      return; # is not a file
204 }
205  
206
207 sub check_file {
208     my($file) = @_;
209     if ($opt_m) {
210         return minus_f_nocase($file) ? $file : "";
211     } else {
212         return minus_f_nocase($file) && containspod($file) ? $file : "";
213     }
214 }
215
216
217 sub searchfor {
218     my($recurse,$s,@dirs) = @_;
219     $s =~ s!::!/!g;
220     $s = VMS::Filespec::unixify($s) if $Is_VMS;
221     return $s if -f $s && containspod($s);
222     printf STDERR "Looking for $s in @dirs\n" if $opt_v;
223     my $ret;
224     my $i;
225     my $dir;
226     $global_target = (split('/', $s))[-1];
227     for ($i=0; $i<@dirs; $i++) {
228         $dir = $dirs[$i];
229         ($dir = VMS::Filespec::unixpath($dir)) =~ s!/$!! if $Is_VMS;
230         if (       ( $ret = check_file "$dir/$s.pod")
231                 or ( $ret = check_file "$dir/$s.pm")
232                 or ( $ret = check_file "$dir/$s")
233                 or ( $Is_VMS and
234                      $ret = check_file "$dir/$s.com")
235                 or ( $^O eq 'os2' and 
236                      $ret = check_file "$dir/$s.cmd")
237                 or ( ($Is_MSWin32 or $Is_Dos or $^O eq 'os2') and
238                      $ret = check_file "$dir/$s.bat")
239                 or ( $ret = check_file "$dir/pod/$s.pod")
240                 or ( $ret = check_file "$dir/pod/$s")
241         ) {
242             return $ret;
243         }
244         
245         if ($recurse) {
246             opendir(D,$dir);
247             my @newdirs = map "$dir/$_", grep {
248                 not /^\.\.?$/ and
249                 not /^auto$/  and   # save time! don't search auto dirs
250                 -d  "$dir/$_"
251             } readdir D;
252             closedir(D);
253             next unless @newdirs;
254             @newdirs = map((s/.dir$//,$_)[1],@newdirs) if $Is_VMS;
255             print STDERR "Also looking in @newdirs\n" if $opt_v;
256             push(@dirs,@newdirs);
257         }
258     }
259     return ();
260 }
261
262
263 foreach (@pages) {
264         if ($podidx && open(PODIDX, $podidx)) {
265             my $searchfor = $_;
266             local($_);
267             $searchfor =~ s,::,/,g;
268             print STDERR "Searching for '$searchfor' in $podidx\n" if $opt_v;
269             while (<PODIDX>) {
270                 chomp;
271                 push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?$,i;
272             }
273             close(PODIDX);
274             next;
275         }
276         print STDERR "Searching for $_\n" if $opt_v;
277         # We must look both in @INC for library modules and in PATH
278         # for executables, like h2xs or perldoc itself.
279         @searchdirs = @INC;
280         if ($opt_F) {
281           next unless -r;
282           push @found, $_ if $opt_m or containspod($_);
283           next;
284         }
285         unless ($opt_m) { 
286             if ($Is_VMS) {
287                 my($i,$trn);
288                 for ($i = 0; $trn = $ENV{'DCL$PATH'.$i}; $i++) {
289                     push(@searchdirs,$trn);
290                 }
291             push(@dirs,'perl_root:[lib.pod]')  # installed pods
292             } else {
293                 push(@searchdirs, grep(-d, split($Config{path_sep}, 
294                                                  $ENV{'PATH'})));
295             }
296             @files= searchfor(0,$_,@searchdirs);
297         }
298         if( @files ) {
299                 print STDERR "Found as @files\n" if $opt_v;
300         } else {
301                 # no match, try recursive search
302                 
303                 @searchdirs = grep(!/^\.$/,@INC);
304                 
305                 @files= searchfor(1,$_,@searchdirs);
306                 if( @files ) {
307                         print STDERR "Loosely found as @files\n" if $opt_v;
308                 } else {
309                         print STDERR "No documentation found for \"$_\".\n";
310                         if (@global_found) {
311                             print STDERR "However, try\n";
312                             my $dir = $file = "";
313                             for $dir (@global_found) {
314                                 opendir(DIR, $dir) or die "$!";
315                                 while ($file = readdir(DIR)) {
316                                     next if ($file =~ /^\./);
317                                     $file =~ s/\.(pm|pod)$//;
318                                     print STDERR "\tperldoc $_\::$file\n";
319                                 }
320                                 closedir DIR;
321                             }
322                         }
323                 }
324         }
325         push(@found,@files);
326 }
327
328 if(!@found) {
329         exit ($Is_VMS ? 98962 : 1);
330 }
331
332 if ($opt_l) {
333     print join("\n", @found), "\n";
334     exit;
335 }
336
337 if( ! -t STDOUT ) { $no_tty = 1 }
338
339 if ($Is_MSWin32) {
340         $tmp = "$ENV{TEMP}\\perldoc1.$$";
341         push @pagers, qw( more< less notepad );
342         unshift @pagers, $ENV{PAGER}  if $ENV{PAGER};
343 } elsif ($Is_VMS) {
344         $tmp = 'Sys$Scratch:perldoc.tmp1_'.$$;
345         push @pagers, qw( most more less type/page );
346 } elsif ($Is_Dos) {
347         $tmp = "$ENV{TEMP}/perldoc1.$$";
348         $tmp =~ tr!\\/!//!s;
349         push @pagers, qw( less.exe more.com< );
350         unshift @pagers, $ENV{PAGER}  if $ENV{PAGER};
351 } else {
352         if ($^O eq 'os2') {
353           require POSIX;
354           $tmp = POSIX::tmpnam();
355         } else {
356           $tmp = "/tmp/perldoc1.$$";      
357         }
358         push @pagers, qw( more less pg view cat );
359         unshift @pagers, $ENV{PAGER}  if $ENV{PAGER};
360 }
361 unshift @pagers, $ENV{PERLDOC_PAGER} if $ENV{PERLDOC_PAGER};
362
363 if ($opt_m) {
364         foreach $pager (@pagers) {
365                 system("$pager @found") or exit;
366         }
367         if ($Is_VMS) { eval 'use vmsish qw(status exit); exit $?' }
368         exit 1;
369
370
371 if ($opt_f) {
372    my $perlfunc = shift @found;
373    open(PFUNC, $perlfunc) or die "Can't open $perlfunc: $!";
374
375    # Skip introduction
376    while (<PFUNC>) {
377        last if /^=head2 Alphabetical Listing of Perl Functions/;
378    }
379
380    # Look for our function
381    my $found = 0;
382    my @pod;
383    while (<PFUNC>) {
384        if (/^=item\s+\Q$opt_f\E\b/o)  {
385            $found = 1;
386        } elsif (/^=item/) {
387            last if $found > 1;
388        }
389        next unless $found;
390        push @pod, $_;
391        ++$found if /^\w/;       # found descriptive text
392    }
393    if (@pod) {
394        if ($opt_t) {
395            open(FORMATTER, "| pod2text") || die "Can't start filter";
396            print FORMATTER "=over 8\n\n";
397            print FORMATTER @pod;
398            print FORMATTER "=back\n";
399            close(FORMATTER);
400        } else {
401            print @pod;
402        }
403    } else {
404        die "No documentation for perl function `$opt_f' found\n";
405    }
406    exit;
407 }
408
409 foreach (@found) {
410
411         if($opt_t) {
412                 open(TMP,">>$tmp");
413                 Pod::Text::pod2text($_,*TMP);
414                 close(TMP);
415         } elsif(not $opt_u) {
416                 my $cmd = "pod2man --lax $_ | nroff -man";
417                 $cmd .= " | col -x" if $^O =~ /hpux/;
418                 $rslt = `$cmd`;
419                 unless(($err = $?)) {
420                         open(TMP,">>$tmp");
421                         print TMP $rslt;
422                         close TMP;
423                 }
424         }
425                                                         
426         if( $opt_u or $err or -z $tmp) {
427                 open(OUT,">>$tmp");
428                 open(IN,"<$_");
429                 $cut = 1;
430                 while (<IN>) {
431                         $cut = $1 eq 'cut' if /^=(\w+)/;
432                         next if $cut;
433                         print OUT;
434                 }
435                 close(IN);
436                 close(OUT);
437         }
438 }
439
440 if( $no_tty ) {
441         open(TMP,"<$tmp");
442         print while <TMP>;
443         close(TMP);
444 } else {
445         foreach $pager (@pagers) {
446                 system("$pager $tmp") or last;
447         }
448 }
449
450 1 while unlink($tmp); #Possibly pointless VMSism
451
452 exit 0;
453
454 __END__
455
456 =head1 NAME
457
458 perldoc - Look up Perl documentation in pod format.
459
460 =head1 SYNOPSIS
461
462 B<perldoc> [B<-h>] [B<-v>] [B<-t>] [B<-u>] [B<-m>] [B<-l>] [B<-F>]  [B<-X>] PageName|ModuleName|ProgramName
463
464 B<perldoc> B<-f> BuiltinFunction
465
466 =head1 DESCRIPTION
467
468 I<perldoc> looks up a piece of documentation in .pod format that is embedded
469 in the perl installation tree or in a perl script, and displays it via
470 C<pod2man | nroff -man | $PAGER>. (In addition, if running under HP-UX,
471 C<col -x> will be used.) This is primarily used for the documentation for
472 the perl library modules.
473
474 Your system may also have man pages installed for those modules, in
475 which case you can probably just use the man(1) command.
476
477 =head1 OPTIONS
478
479 =over 5
480
481 =item B<-h> help
482
483 Prints out a brief help message.
484
485 =item B<-v> verbose
486
487 Describes search for the item in detail.
488
489 =item B<-t> text output
490
491 Display docs using plain text converter, instead of nroff. This may be faster,
492 but it won't look as nice.
493
494 =item B<-u> unformatted
495
496 Find docs only; skip reformatting by pod2*
497
498 =item B<-m> module
499
500 Display the entire module: both code and unformatted pod documentation.
501 This may be useful if the docs don't explain a function in the detail
502 you need, and you'd like to inspect the code directly; perldoc will find
503 the file for you and simply hand it off for display.
504
505 =item B<-l> file name only
506
507 Display the file name of the module found.
508
509 =item B<-F> file names
510
511 Consider arguments as file names, no search in directories will be performed.
512
513 =item B<-f> perlfunc
514
515 The B<-f> option followed by the name of a perl built in function will
516 extract the documentation of this function from L<perlfunc>.
517
518 =item B<-X> use an index if present
519
520 The B<-X> option looks for a entry whose basename matches the name given on the
521 command line in the file C<$Config{archlib}/pod.idx>.  The pod.idx file should
522 contain fully qualified filenames, one per line.
523
524 =item B<PageName|ModuleName|ProgramName>
525
526 The item you want to look up.  Nested modules (such as C<File::Basename>)
527 are specified either as C<File::Basename> or C<File/Basename>.  You may also
528 give a descriptive name of a page, such as C<perlfunc>. You make also give a
529 partial or wrong-case name, such as "basename" for "File::Basename", but
530 this will be slower, if there is more then one page with the same partial
531 name, you will only get the first one.
532
533 =back
534
535 =head1 ENVIRONMENT
536
537 Any switches in the C<PERLDOC> environment variable will be used before the 
538 command line arguments.  C<perldoc> also searches directories
539 specified by the C<PERL5LIB> (or C<PERLLIB> if C<PERL5LIB> is not
540 defined) and C<PATH> environment variables.
541 (The latter is so that embedded pods for executables, such as
542 C<perldoc> itself, are available.)
543
544 =head1 AUTHOR
545
546 Kenneth Albanowski <kjahds@kjahds.com>
547
548 Minor updates by Andy Dougherty <doughera@lafcol.lafayette.edu>
549
550 =cut
551
552 #
553 # Version 1.13: Fri Feb 27 16:20:50 EST 1997
554 #       Gurusamy Sarathy <gsar@umich.edu>
555 #       -doc tweaks for -F and -X options
556 # Version 1.12: Sat Apr 12 22:41:09 EST 1997
557 #       Gurusamy Sarathy <gsar@umich.edu>
558 #       -various fixes for win32
559 # Version 1.11: Tue Dec 26 09:54:33 EST 1995
560 #       Kenneth Albanowski <kjahds@kjahds.com>
561 #   -added Charles Bailey's further VMS patches, and -u switch
562 #   -added -t switch, with pod2text support
563
564 # Version 1.10: Thu Nov  9 07:23:47 EST 1995
565 #               Kenneth Albanowski <kjahds@kjahds.com>
566 #       -added VMS support
567 #       -added better error recognition (on no found pages, just exit. On
568 #        missing nroff/pod2man, just display raw pod.)
569 #       -added recursive/case-insensitive matching (thanks, Andreas). This
570 #        slows things down a bit, unfortunately. Give a precise name, and
571 #        it'll run faster.
572 #
573 # Version 1.01: Tue May 30 14:47:34 EDT 1995
574 #               Andy Dougherty  <doughera@lafcol.lafayette.edu>
575 #   -added pod documentation.
576 #   -added PATH searching.
577 #   -added searching pod/ subdirectory (mainly to pick up perlfunc.pod
578 #    and friends.
579 #
580 #
581 # TODO:
582 #
583 #       Cache directories read during sloppy match
584 !NO!SUBS!
585
586 close OUT or die "Can't close $file: $!";
587 chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
588 exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';