752f335ca290af8d22123c6f1da9b35488fe3b0a
[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         my $lines = $ENV{LINES} || 24;
395
396        if ($opt_t) {
397            open(FORMATTER, "| pod2text") || die "Can't start filter";
398            print FORMATTER "=over 8\n\n";
399            print FORMATTER @pod;
400            print FORMATTER "=back\n";
401            close(FORMATTER);
402        } elsif (@pod < $lines-2) {
403            print @pod;
404        } else {
405            foreach $pager (@pagers) {
406                 open (PAGER, "| $pager") or next;
407                 print PAGER @pod ;
408                 close(PAGER) or next;
409                 last;
410            }
411        }
412    } else {
413        die "No documentation for perl function `$opt_f' found\n";
414    }
415    exit;
416 }
417
418 foreach (@found) {
419
420         if($opt_t) {
421                 open(TMP,">>$tmp");
422                 Pod::Text::pod2text($_,*TMP);
423                 close(TMP);
424         } elsif(not $opt_u) {
425                 my $cmd = "pod2man --lax $_ | nroff -man";
426                 $cmd .= " | col -x" if $^O =~ /hpux/;
427                 $rslt = `$cmd`;
428                 unless(($err = $?)) {
429                         open(TMP,">>$tmp");
430                         print TMP $rslt;
431                         close TMP;
432                 }
433         }
434                                                         
435         if( $opt_u or $err or -z $tmp) {
436                 open(OUT,">>$tmp");
437                 open(IN,"<$_");
438                 $cut = 1;
439                 while (<IN>) {
440                         $cut = $1 eq 'cut' if /^=(\w+)/;
441                         next if $cut;
442                         print OUT;
443                 }
444                 close(IN);
445                 close(OUT);
446         }
447 }
448
449 if( $no_tty ) {
450         open(TMP,"<$tmp");
451         print while <TMP>;
452         close(TMP);
453 } else {
454         foreach $pager (@pagers) {
455                 system("$pager $tmp") or last;
456         }
457 }
458
459 1 while unlink($tmp); #Possibly pointless VMSism
460
461 exit 0;
462
463 __END__
464
465 =head1 NAME
466
467 perldoc - Look up Perl documentation in pod format.
468
469 =head1 SYNOPSIS
470
471 B<perldoc> [B<-h>] [B<-v>] [B<-t>] [B<-u>] [B<-m>] [B<-l>] [B<-F>]  [B<-X>] PageName|ModuleName|ProgramName
472
473 B<perldoc> B<-f> BuiltinFunction
474
475 =head1 DESCRIPTION
476
477 I<perldoc> looks up a piece of documentation in .pod format that is embedded
478 in the perl installation tree or in a perl script, and displays it via
479 C<pod2man | nroff -man | $PAGER>. (In addition, if running under HP-UX,
480 C<col -x> will be used.) This is primarily used for the documentation for
481 the perl library modules.
482
483 Your system may also have man pages installed for those modules, in
484 which case you can probably just use the man(1) command.
485
486 =head1 OPTIONS
487
488 =over 5
489
490 =item B<-h> help
491
492 Prints out a brief help message.
493
494 =item B<-v> verbose
495
496 Describes search for the item in detail.
497
498 =item B<-t> text output
499
500 Display docs using plain text converter, instead of nroff. This may be faster,
501 but it won't look as nice.
502
503 =item B<-u> unformatted
504
505 Find docs only; skip reformatting by pod2*
506
507 =item B<-m> module
508
509 Display the entire module: both code and unformatted pod documentation.
510 This may be useful if the docs don't explain a function in the detail
511 you need, and you'd like to inspect the code directly; perldoc will find
512 the file for you and simply hand it off for display.
513
514 =item B<-l> file name only
515
516 Display the file name of the module found.
517
518 =item B<-F> file names
519
520 Consider arguments as file names, no search in directories will be performed.
521
522 =item B<-f> perlfunc
523
524 The B<-f> option followed by the name of a perl built in function will
525 extract the documentation of this function from L<perlfunc>.
526
527 =item B<-X> use an index if present
528
529 The B<-X> option looks for a entry whose basename matches the name given on the
530 command line in the file C<$Config{archlib}/pod.idx>.  The pod.idx file should
531 contain fully qualified filenames, one per line.
532
533 =item B<PageName|ModuleName|ProgramName>
534
535 The item you want to look up.  Nested modules (such as C<File::Basename>)
536 are specified either as C<File::Basename> or C<File/Basename>.  You may also
537 give a descriptive name of a page, such as C<perlfunc>. You make also give a
538 partial or wrong-case name, such as "basename" for "File::Basename", but
539 this will be slower, if there is more then one page with the same partial
540 name, you will only get the first one.
541
542 =back
543
544 =head1 ENVIRONMENT
545
546 Any switches in the C<PERLDOC> environment variable will be used before the 
547 command line arguments.  C<perldoc> also searches directories
548 specified by the C<PERL5LIB> (or C<PERLLIB> if C<PERL5LIB> is not
549 defined) and C<PATH> environment variables.
550 (The latter is so that embedded pods for executables, such as
551 C<perldoc> itself, are available.)
552
553 =head1 AUTHOR
554
555 Kenneth Albanowski <kjahds@kjahds.com>
556
557 Minor updates by Andy Dougherty <doughera@lafcol.lafayette.edu>
558
559 =cut
560
561 #
562 # Version 1.13: Fri Feb 27 16:20:50 EST 1997
563 #       Gurusamy Sarathy <gsar@umich.edu>
564 #       -doc tweaks for -F and -X options
565 # Version 1.12: Sat Apr 12 22:41:09 EST 1997
566 #       Gurusamy Sarathy <gsar@umich.edu>
567 #       -various fixes for win32
568 # Version 1.11: Tue Dec 26 09:54:33 EST 1995
569 #       Kenneth Albanowski <kjahds@kjahds.com>
570 #   -added Charles Bailey's further VMS patches, and -u switch
571 #   -added -t switch, with pod2text support
572
573 # Version 1.10: Thu Nov  9 07:23:47 EST 1995
574 #               Kenneth Albanowski <kjahds@kjahds.com>
575 #       -added VMS support
576 #       -added better error recognition (on no found pages, just exit. On
577 #        missing nroff/pod2man, just display raw pod.)
578 #       -added recursive/case-insensitive matching (thanks, Andreas). This
579 #        slows things down a bit, unfortunately. Give a precise name, and
580 #        it'll run faster.
581 #
582 # Version 1.01: Tue May 30 14:47:34 EDT 1995
583 #               Andy Dougherty  <doughera@lafcol.lafayette.edu>
584 #   -added pod documentation.
585 #   -added PATH searching.
586 #   -added searching pod/ subdirectory (mainly to pick up perlfunc.pod
587 #    and friends.
588 #
589 #
590 # TODO:
591 #
592 #       Cache directories read during sloppy match
593 !NO!SUBS!
594
595 close OUT or die "Can't close $file: $!";
596 chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
597 exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';