home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl560.zip / utils / perldoc.PL < prev    next >
Perl Script  |  2000-03-13  |  23KB  |  857 lines

  1. #!/usr/local/bin/perl
  2.  
  3. use Config;
  4. use File::Basename qw(&basename &dirname);
  5. use Cwd;
  6.  
  7. # List explicitly here the variables you want Configure to
  8. # generate.  Metaconfig only looks for shell variables, so you
  9. # have to mention them as if they were shell variables, not
  10. # %Config entries.  Thus you write
  11. #  $startperl
  12. # to ensure Configure will look for $Config{startperl}.
  13.  
  14. # This forces PL files to create target in same directory as PL file.
  15. # This is so that make depend always knows where to find PL derivatives.
  16. $origdir = cwd;
  17. chdir dirname($0);
  18. $file = basename($0, '.PL');
  19. $file .= '.com' if $^O eq 'VMS';
  20.  
  21. open OUT,">$file" or die "Can't create $file: $!";
  22.  
  23. print "Extracting $file (with variable substitutions)\n";
  24.  
  25. # In this section, perl variables will be expanded during extraction.
  26. # You can use $Config{...} to use Configure variables.
  27.  
  28. print OUT <<"!GROK!THIS!";
  29. $Config{startperl}
  30.     eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}'
  31.     if 0;
  32.  
  33. use warnings;
  34. use strict;
  35.  
  36. # make sure creat()s are neither too much nor too little
  37. INIT { eval { umask(0077) } }   # doubtless someone has no mask
  38.  
  39. my \@pagers = ();
  40. push \@pagers, "$Config{'pager'}" if -x "$Config{'pager'}";
  41.  
  42. !GROK!THIS!
  43.  
  44. # In the following, perl variables are not expanded during extraction.
  45.  
  46. print OUT <<'!NO!SUBS!';
  47.  
  48. use Fcntl;    # for sysopen
  49. use Getopt::Std;
  50. use Config '%Config';
  51.  
  52. #
  53. # Perldoc revision #1 -- look up a piece of documentation in .pod format that
  54. # is embedded in the perl installation tree.
  55. #
  56. # This is not to be confused with Tom Christiansen's perlman, which is a
  57. # man replacement, written in perl. This perldoc is strictly for reading
  58. # the perl manuals, though it too is written in perl.
  59. # Massive security and correctness patches applied to this
  60. # noisome program by Tom Christiansen Sat Mar 11 15:22:33 MST 2000 
  61.  
  62. if (@ARGV<1) {
  63.     my $me = $0;        # Editing $0 is unportable
  64.     $me =~ s,.*/,,;
  65.     die <<EOF;
  66. Usage: $me [-h] [-r] [-i] [-v] [-t] [-u] [-m] [-n program] [-l] [-F] [-X] PageName|ModuleName|ProgramName
  67.        $me -f PerlFunc
  68.        $me -q FAQKeywords
  69.  
  70. The -h option prints more help.  Also try "perldoc perldoc" to get
  71. acquainted with the system.
  72. EOF
  73. }
  74.  
  75. my @global_found = ();
  76. my $global_target = "";
  77.  
  78. my $Is_VMS = $^O eq 'VMS';
  79. my $Is_MSWin32 = $^O eq 'MSWin32';
  80. my $Is_Dos = $^O eq 'dos';
  81.  
  82. sub usage{
  83.     warn "@_\n" if @_;
  84.     # Erase evidence of previous errors (if any), so exit status is simple.
  85.     $! = 0;
  86.     die <<EOF;
  87. perldoc [options] PageName|ModuleName|ProgramName...
  88. perldoc [options] -f BuiltinFunction
  89. perldoc [options] -q FAQRegex
  90.  
  91. Options:
  92.     -h   Display this help message
  93.     -r   Recursive search (slow)
  94.     -i   Ignore case
  95.     -t   Display pod using pod2text instead of pod2man and nroff
  96.              (-t is the default on win32)
  97.     -u     Display unformatted pod text
  98.     -m   Display module's file in its entirety
  99.     -n   Specify replacement for nroff
  100.     -l   Display the module's file name
  101.     -F   Arguments are file names, not modules
  102.     -v     Verbosely describe what's going on
  103.     -X     use index if present (looks for pod.idx at $Config{archlib})
  104.     -q   Search the text of questions (not answers) in perlfaq[1-9]
  105.     -U     Run in insecure mode (superuser only)
  106.  
  107. PageName|ModuleName...
  108.          is the name of a piece of documentation that you want to look at. You
  109.          may either give a descriptive name of the page (as in the case of
  110.          `perlfunc') the name of a module, either like `Term::Info',
  111.          `Term/Info', the partial name of a module, like `info', or
  112.          `makemaker', or the name of a program, like `perldoc'.
  113.  
  114. BuiltinFunction
  115.          is the name of a perl function.  Will extract documentation from
  116.          `perlfunc'.
  117.  
  118. FAQRegex
  119.          is a regex. Will search perlfaq[1-9] for and extract any
  120.          questions that match.
  121.  
  122. Any switches in the PERLDOC environment variable will be used before the
  123. command line arguments.  The optional pod index file contains a list of
  124. filenames, one per line.
  125.  
  126. EOF
  127. }
  128.  
  129. if (defined $ENV{"PERLDOC"}) {
  130.     require Text::ParseWords;
  131.     unshift(@ARGV, Text::ParseWords::shellwords($ENV{"PERLDOC"}));
  132. }
  133. !NO!SUBS!
  134.  
  135. my $getopts = "mhtluvriFf:Xq:n:U";
  136. print OUT <<"!GET!OPTS!";
  137.  
  138. use vars qw( @{[map "\$opt_$_", ($getopts =~ /\w/g)]} );
  139.  
  140. getopts("$getopts") || usage;
  141. !GET!OPTS!
  142.  
  143. print OUT <<'!NO!SUBS!';
  144.  
  145. usage if $opt_h;
  146.  
  147. # refuse to run if we should be tainting and aren't
  148. # (but regular users deserve protection too, though!)
  149. if (!($Is_VMS || $Is_MSWin32 || $Is_Dos) && ($> == 0 || $< == 0)
  150.      && !am_taint_checking()) 
  151. {{
  152.     if ($opt_U) {
  153.         my $id = eval { getpwnam("nobody") };
  154.            $id = eval { getpwnam("nouser") } unless defined $id;
  155.            $id = -2 unless defined $id;
  156.         eval {
  157.             $> = $id;  # must do this one first!
  158.             $< = $id;
  159.         };
  160.         last if !$@ && $< && $>;
  161.     }
  162.     die "Superuser must not run $0 without security audit and taint checks.\n";
  163. }}
  164.  
  165. $opt_n = "nroff" if !$opt_n;
  166.  
  167. my $podidx;
  168. if ($opt_X) {
  169.     $podidx = "$Config{'archlib'}/pod.idx";
  170.     $podidx = "" unless -f $podidx && -r _ && -M _ <= 7;
  171. }
  172.  
  173. if ((my $opts = do{ no warnings; $opt_t + $opt_u + $opt_m + $opt_l }) > 1) {
  174.     usage("only one of -t, -u, -m or -l")
  175. }
  176. elsif ($Is_MSWin32
  177.        || $Is_Dos
  178.        || !($ENV{TERM} && $ENV{TERM} !~ /dumb|emacs|none|unknown/i))
  179. {
  180.     $opt_t = 1 unless $opts;
  181. }
  182.  
  183. if ($opt_t) { require Pod::Text; import Pod::Text; }
  184.  
  185. my @pages;
  186. if ($opt_f) {
  187.     @pages = ("perlfunc");
  188. }
  189. elsif ($opt_q) {
  190.     @pages = ("perlfaq1" .. "perlfaq9");
  191. }
  192. else {
  193.     @pages = @ARGV;
  194. }
  195.  
  196. # Does this look like a module or extension directory?
  197. if (-f "Makefile.PL") {
  198.  
  199.     # Add ., lib to @INC (if they exist)
  200.     eval q{ use lib qw(. lib); 1; } or die;
  201.  
  202.     # don't add if superuser
  203.     if ($< && $>) {   # don't be looking too hard now!
  204.     eval q{ use blib; 1 } or die;
  205.     }
  206. }
  207.  
  208. sub containspod {
  209.     my($file, $readit) = @_;
  210.     return 1 if !$readit && $file =~ /\.pod\z/i;
  211.     local($_);
  212.     open(TEST,"<", $file)     or die "Can't open $file: $!";
  213.     while (<TEST>) {
  214.     if (/^=head/) {
  215.         close(TEST)     or die "Can't close $file: $!";
  216.         return 1;
  217.     }
  218.     }
  219.     close(TEST)         or die "Can't close $file: $!";
  220.     return 0;
  221. }
  222.  
  223. sub minus_f_nocase {
  224.      my($dir,$file) = @_;
  225.      my $path = join('/',$dir,$file);    # XXX: dirseps
  226.      return $path if -f $path and -r _;
  227.      if (!$opt_i or $Is_VMS or $Is_MSWin32 or $Is_Dos or $^O eq 'os2') {
  228.         # on a case-forgiving file system or if case is important
  229.     # that is it all we can do
  230.     warn "Ignored $path: unreadable\n" if -f _;
  231.     return '';
  232.      }
  233.      local *DIR;
  234.      # this is completely wicked.  don't mess with $", and if 
  235.      # you do, don't assume / is the dirsep!
  236.      local($")="/";
  237.      my @p = ($dir);
  238.      my($p,$cip);
  239.      foreach $p (split(m!/!, $file)){    # XXX: dirseps
  240.     my $try = "@p/$p";
  241.     stat $try;
  242.      if (-d _) {
  243.          push @p, $p;
  244.         if ( $p eq $global_target) {
  245.         my $tmp_path = join ('/', @p);  # XXX: dirseps
  246.         my $path_f = 0;
  247.         for (@global_found) {
  248.             $path_f = 1 if $_ eq $tmp_path;
  249.         }
  250.         push (@global_found, $tmp_path) unless $path_f;
  251.         print STDERR "Found as @p but directory\n" if $opt_v;
  252.         }
  253.      }
  254.     elsif (-f _ && -r _) {
  255.          return $try;
  256.      }
  257.     elsif (-f _) {
  258.         warn "Ignored $try: unreadable\n";
  259.      }
  260.     elsif (-d "@p") {
  261.          my $found=0;
  262.          my $lcp = lc $p;
  263.          opendir DIR, "@p"         or die "opendir @p: $!";
  264.          while ($cip=readdir(DIR)) {
  265.          if (lc $cip eq $lcp){
  266.              $found++;
  267.              last;
  268.          }
  269.          }
  270.          closedir DIR        or die "closedir @p: $!";
  271.          return "" unless $found;
  272.          push @p, $cip;
  273.          return "@p" if -f "@p" and -r _;
  274.         warn "Ignored @p: unreadable\n" if -f _;
  275.      }
  276.      }
  277.      return "";
  278. }
  279.  
  280.  
  281. sub check_file {
  282.     my($dir,$file) = @_;
  283.     return "" if length $dir and not -d $dir;
  284.     if ($opt_m) {
  285.     return minus_f_nocase($dir,$file);
  286.     }
  287.     else {
  288.     my $path = minus_f_nocase($dir,$file);
  289.         return $path if length $path and containspod($path);
  290.     }
  291.     return "";
  292. }
  293.  
  294.  
  295. sub searchfor {
  296.     my($recurse,$s,@dirs) = @_;
  297.     $s =~ s!::!/!g;
  298.     $s = VMS::Filespec::unixify($s) if $Is_VMS;
  299.     return $s if -f $s && containspod($s);
  300.     printf STDERR "Looking for $s in @dirs\n" if $opt_v;
  301.     my $ret;
  302.     my $i;
  303.     my $dir;
  304.     $global_target = (split(m!/!, $s))[-1];   # XXX: dirseps
  305.     for ($i=0; $i<@dirs; $i++) {
  306.     $dir = $dirs[$i];
  307.     ($dir = VMS::Filespec::unixpath($dir)) =~ s!/\z!! if $Is_VMS;
  308.     if (       ( $ret = check_file $dir,"$s.pod")
  309.         or ( $ret = check_file $dir,"$s.pm")
  310.         or ( $ret = check_file $dir,$s)
  311.         or ( $Is_VMS and
  312.              $ret = check_file $dir,"$s.com")
  313.         or ( $^O eq 'os2' and
  314.              $ret = check_file $dir,"$s.cmd")
  315.         or ( ($Is_MSWin32 or $Is_Dos or $^O eq 'os2') and
  316.              $ret = check_file $dir,"$s.bat")
  317.         or ( $ret = check_file "$dir/pod","$s.pod")
  318.         or ( $ret = check_file "$dir/pod",$s)
  319.         or ( $ret = check_file "$dir/pods","$s.pod")
  320.         or ( $ret = check_file "$dir/pods",$s)
  321.     ) {
  322.         return $ret;
  323.     }
  324.  
  325.     if ($recurse) {
  326.         opendir(D,$dir)    or die "Can't opendir $dir: $!";
  327.         my @newdirs = map "$dir/$_", grep {  # XXX: dirseps
  328.         not /^\.\.?\z/s and
  329.         not /^auto\z/s  and   # save time! don't search auto dirs
  330.         -d  "$dir/$_"  # XXX: dirseps
  331.         } readdir D;
  332.         closedir(D)        or die "Can't closedir $dir: $!";
  333.         next unless @newdirs;
  334.         # what a wicked map!
  335.         @newdirs = map((s/\.dir\z//,$_)[1],@newdirs) if $Is_VMS;
  336.         print STDERR "Also looking in @newdirs\n" if $opt_v;
  337.         push(@dirs,@newdirs);
  338.     }
  339.     }
  340.     return ();
  341. }
  342.  
  343. sub filter_nroff {
  344.   my @data = split /\n{2,}/, shift;
  345.   shift @data while @data and $data[0] !~ /\S/; # Go to header
  346.   shift @data if @data and $data[0] =~ /Contributed\s+Perl/; # Skip header
  347.   pop @data if @data and $data[-1] =~ /^\w/; # Skip footer, like
  348.                 # 28/Jan/99 perl 5.005, patch 53 1
  349.   join "\n\n", @data;
  350. }
  351.  
  352. sub printout {
  353.     my ($file, $tmp, $filter) = @_;
  354.     my $err;
  355.  
  356.     if ($opt_t) {
  357.     # why was this append?
  358.     sysopen(OUT, $tmp, O_WRONLY | O_EXCL | O_CREAT, 0600)
  359.         or die ("Can't open $tmp: $!");
  360.     Pod::Text->new()->parse_from_file($file,\*OUT);
  361.     close OUT   or die "can't close $tmp: $!";
  362.     }
  363.     elsif (not $opt_u) {
  364.     my $cmd = "pod2man --lax $file | $opt_n -man";
  365.     $cmd .= " | col -x" if $^O =~ /hpux/;
  366.     my $rslt = `$cmd`;
  367.     $rslt = filter_nroff($rslt) if $filter;
  368.     unless (($err = $?)) {
  369.         # why was this append?
  370.         sysopen(TMP, $tmp, O_WRONLY | O_EXCL | O_CREAT, 0600)
  371.         or die "Can't open $tmp: $!";
  372.         print TMP $rslt
  373.         or die "Can't print $tmp: $!";
  374.         close TMP
  375.         or die "Can't close $tmp: $!";
  376.     }
  377.     }
  378.     if ($opt_u or $err or -z $tmp) {  # XXX: race with -z
  379.     # why was this append?
  380.     sysopen(OUT, $tmp, O_WRONLY | O_EXCL | O_CREAT, 0600)
  381.         or die "Can't open $tmp: $!";
  382.     open(IN,"<", $file)   or die("Can't open $file: $!");
  383.     my $cut = 1;
  384.     local $_;
  385.     while (<IN>) {
  386.         $cut = $1 eq 'cut' if /^=(\w+)/;
  387.         next if $cut;
  388.         print OUT
  389.         or die "Can't print $tmp: $!";
  390.     }
  391.     close IN    or die "Can't close $file: $!";
  392.     close OUT   or die "Can't close $tmp: $!";
  393.     }
  394. }
  395.  
  396. sub page {
  397.     my ($tmp, $no_tty, @pagers) = @_;
  398.     if ($no_tty) {
  399.     open(TMP,"<", $tmp)     or die "Can't open $tmp: $!";
  400.     local $_;
  401.     while (<TMP>) {
  402.         print or die "Can't print to stdout: $!";
  403.     } 
  404.     close TMP        or die "Can't close while $tmp: $!";
  405.     }
  406.     else {
  407.     foreach my $pager (@pagers) {
  408.         last if system("$pager $tmp") == 0;
  409.     }
  410.     }
  411. }
  412.  
  413. sub cleanup {
  414.     my @files = @_;
  415.     for (@files) {
  416.     if ($Is_VMS) { 
  417.         1 while unlink($_);    # XXX: expect failure
  418.     } else {
  419.         unlink($_);           # or die "Can't unlink $_: $!";
  420.     } 
  421.     }
  422. }
  423.  
  424. my @found;
  425. foreach (@pages) {
  426.     if ($podidx && open(PODIDX, $podidx)) {
  427.     my $searchfor = $_;
  428.     $searchfor =~ s,::,/,g;        # XXX: dirseps
  429.     print STDERR "Searching for '$searchfor' in $podidx\n" if $opt_v;
  430.     local $_;
  431.     while (<PODIDX>) {
  432.         chomp;
  433.         push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?\z,i;
  434.     }
  435.     close(PODIDX)        or die "Can't close $podidx: $!";
  436.     next;
  437.     }
  438.     print STDERR "Searching for $_\n" if $opt_v;
  439.     # We must look both in @INC for library modules and in PATH
  440.     # for executables, like h2xs or perldoc itself.
  441.     my @searchdirs = @INC;
  442.     if ($opt_F) {
  443.     next unless -r;
  444.     push @found, $_ if $opt_m or containspod($_);
  445.     next;
  446.     }
  447.     unless ($opt_m) {
  448.     if ($Is_VMS) {
  449.         my($i,$trn);
  450.         for ($i = 0; $trn = $ENV{'DCL$PATH;'.$i}; $i++) {
  451.         push(@searchdirs,$trn);
  452.         }
  453.         push(@searchdirs,'perl_root:[lib.pod]')  # installed pods
  454.     }
  455.     else {
  456.         push(@searchdirs, grep(-d, split($Config{path_sep},
  457.                          $ENV{'PATH'})));
  458.     }
  459.     }
  460.     my @files = searchfor(0,$_,@searchdirs);
  461.     if (@files) {
  462.     print STDERR "Found as @files\n" if $opt_v;
  463.     }
  464.     else {
  465.     # no match, try recursive search
  466.     @searchdirs = grep(!/^\.\z/s,@INC);
  467.     @files= searchfor(1,$_,@searchdirs) if $opt_r;
  468.     if (@files) {
  469.         print STDERR "Loosely found as @files\n" if $opt_v;
  470.     }
  471.     else {
  472.         print STDERR "No documentation found for \"$_\".\n";
  473.         if (@global_found) {
  474.         print STDERR "However, try\n";
  475.         for my $dir (@global_found) {
  476.             opendir(DIR, $dir) or die "opendir $dir: $!";
  477.             while (my $file = readdir(DIR)) {
  478.             next if ($file =~ /^\./s);
  479.             $file =~ s/\.(pm|pod)\z//;  # XXX: badfs
  480.             print STDERR "\tperldoc $_\::$file\n";
  481.             }
  482.             closedir DIR    or die "closedir $dir: $!";
  483.         }
  484.         }
  485.     }
  486.     }
  487.     push(@found,@files);
  488. }
  489.  
  490. if (!@found) {
  491.     exit ($Is_VMS ? 98962 : 1);
  492. }
  493.  
  494. if ($opt_l) {
  495.     print join("\n", @found), "\n";
  496.     exit;
  497. }
  498.  
  499. my $lines = $ENV{LINES} || 24;
  500.  
  501. my $no_tty;
  502. if (! -t STDOUT) { $no_tty = 1 }
  503. END { close(STDOUT) || die "Can't close STDOUT: $!" }
  504.  
  505. # until here we could simply exit or die
  506. # now we create temporary files that we have to clean up
  507. # namely $tmp, $buffer
  508. # that's because you did it wrong, should be descriptor based --tchrist
  509.  
  510. my $tmp;
  511. my $buffer;
  512. if ($Is_MSWin32) {
  513.     $tmp = "$ENV{TEMP}\\perldoc1.$$";
  514.     $buffer = "$ENV{TEMP}\\perldoc1.b$$";
  515.     push @pagers, qw( more< less notepad );
  516.     unshift @pagers, $ENV{PAGER}  if $ENV{PAGER};
  517.     for (@found) { s,/,\\,g }
  518. }
  519. elsif ($Is_VMS) {
  520.     $tmp = 'Sys$Scratch:perldoc.tmp1_'.$$;
  521.     $buffer = 'Sys$Scratch:perldoc.tmp1_b'.$$;
  522.     push @pagers, qw( most more less type/page );
  523. }
  524. elsif ($Is_Dos) {
  525.     $tmp = "$ENV{TEMP}/perldoc1.$$";
  526.     $buffer = "$ENV{TEMP}/perldoc1.b$$";
  527.     $tmp =~ tr!\\/!//!s;
  528.     $buffer =~ tr!\\/!//!s;
  529.     push @pagers, qw( less.exe more.com< );
  530.     unshift @pagers, $ENV{PAGER}  if $ENV{PAGER};
  531. }
  532. else {
  533.     if ($^O eq 'os2') {
  534.       require POSIX;
  535.       $tmp = POSIX::tmpnam();
  536.       $buffer = POSIX::tmpnam();
  537.       unshift @pagers, 'less', 'cmd /c more <';
  538.     }
  539.     else {
  540.       # XXX: this is not secure, because it doesn't open it
  541.       ($tmp, $buffer) = eval { require POSIX } 
  542.         ? (POSIX::tmpnam(),    POSIX::tmpnam()     )
  543.         : ("/tmp/perldoc1.$$", "/tmp/perldoc1.b$$" );
  544.     }
  545.     push @pagers, qw( more less pg view cat );
  546.     unshift @pagers, $ENV{PAGER}  if $ENV{PAGER};
  547. }
  548. unshift @pagers, $ENV{PERLDOC_PAGER} if $ENV{PERLDOC_PAGER};
  549.  
  550. # make sure cleanup called
  551. eval q{
  552.     sub END { cleanup($tmp, $buffer) } 
  553.     1;
  554. } || die;
  555. eval q{ use sigtrap qw(die INT TERM HUP QUIT) };
  556.  
  557. if ($opt_m) {
  558.     foreach my $pager (@pagers) {
  559.     if (system($pager, @found) == 0) {
  560.         exit;
  561.     }
  562.     }
  563.     if ($Is_VMS) { 
  564.     eval q{
  565.         use vmsish qw(status exit); 
  566.         exit $?;
  567.         1;
  568.     } or die;
  569.     }
  570.     exit(1);
  571. }
  572.  
  573. my @pod;
  574. if ($opt_f) {
  575.     my $perlfunc = shift @found;
  576.     open(PFUNC, "<", $perlfunc)
  577.     or die("Can't open $perlfunc: $!");
  578.  
  579.     # Functions like -r, -e, etc. are listed under `-X'.
  580.     my $search_string = ($opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/)
  581.             ? 'I<-X' : $opt_f ;
  582.  
  583.     # Skip introduction
  584.     local $_;
  585.     while (<PFUNC>) {
  586.     last if /^=head2 Alphabetical Listing of Perl Functions/;
  587.     }
  588.  
  589.     # Look for our function
  590.     my $found = 0;
  591.     my $inlist = 0;
  592.     while (<PFUNC>) {
  593.     if (/^=item\s+\Q$search_string\E\b/o)  {
  594.         $found = 1;
  595.     }
  596.     elsif (/^=item/) {
  597.         last if $found > 1 and not $inlist;
  598.     }
  599.     next unless $found;
  600.     if (/^=over/) {
  601.         ++$inlist;
  602.     }
  603.     elsif (/^=back/) {
  604.         --$inlist;
  605.     }
  606.     push @pod, $_;
  607.     ++$found if /^\w/;    # found descriptive text
  608.     }
  609.     if (!@pod) {
  610.     die "No documentation for perl function `$opt_f' found\n";
  611.     }
  612.     close PFUNC        or die "Can't open $perlfunc: $!";
  613. }
  614.  
  615. if ($opt_q) {
  616.     local @ARGV = @found;    # I'm lazy, sue me.
  617.     my $found = 0;
  618.     my %found_in;
  619.     my $rx = eval { qr/$opt_q/ } or die <<EOD;
  620. Invalid regular expression '$opt_q' given as -q pattern:
  621.   $@
  622. Did you mean \\Q$opt_q ?
  623.  
  624. EOD
  625.  
  626.     for (@found) { die "invalid file spec: $!" if /[<>|]/ } 
  627.     local $_;
  628.     while (<>) {
  629.     if (/^=head2\s+.*(?:$opt_q)/oi) {
  630.         $found = 1;
  631.         push @pod, "=head1 Found in $ARGV\n\n" unless $found_in{$ARGV}++;
  632.     }
  633.     elsif (/^=head2/) {
  634.         $found = 0;
  635.     }
  636.     next unless $found;
  637.     push @pod, $_;
  638.     }
  639.     if (!@pod) {
  640.     die("No documentation for perl FAQ keyword `$opt_q' found\n");
  641.     }
  642. }
  643.  
  644. my $filter;
  645.  
  646. if (@pod) {
  647.     sysopen(TMP, $buffer, O_WRONLY | O_EXCL | O_CREAT)
  648.     or die("Can't open $buffer: $!");
  649.     print TMP "=over 8\n\n";
  650.     print TMP @pod    or die "Can't print $buffer: $!";
  651.     print TMP "=back\n";
  652.     close TMP        or die "Can't close $buffer: $!";
  653.     @found = $buffer;
  654.     $filter = 1;
  655. }
  656.  
  657. foreach (@found) {
  658.     printout($_, $tmp, $filter);
  659. }
  660. page($tmp, $no_tty, @pagers);
  661.  
  662. exit;
  663.  
  664. sub is_tainted {
  665.     my $arg = shift;
  666.     my $nada = substr($arg, 0, 0);  # zero-length
  667.     local $@;  # preserve caller's version
  668.     eval { eval "# $nada" };
  669.     return length($@) != 0;
  670. }
  671.  
  672. sub am_taint_checking {
  673.     my($k,$v) = each %ENV;
  674.     return is_tainted($v);  
  675. }
  676.  
  677.  
  678. __END__
  679.  
  680. =head1 NAME
  681.  
  682. perldoc - Look up Perl documentation in pod format.
  683.  
  684. =head1 SYNOPSIS
  685.  
  686. B<perldoc> [B<-h>] [B<-v>] [B<-t>] [B<-u>] [B<-m>] [B<-l>] [B<-F>]  [B<-X>] PageName|ModuleName|ProgramName
  687.  
  688. B<perldoc> B<-f> BuiltinFunction
  689.  
  690. B<perldoc> B<-q> FAQ Keyword
  691.  
  692. =head1 DESCRIPTION
  693.  
  694. I<perldoc> looks up a piece of documentation in .pod format that is embedded
  695. in the perl installation tree or in a perl script, and displays it via
  696. C<pod2man | nroff -man | $PAGER>. (In addition, if running under HP-UX,
  697. C<col -x> will be used.) This is primarily used for the documentation for
  698. the perl library modules.
  699.  
  700. Your system may also have man pages installed for those modules, in
  701. which case you can probably just use the man(1) command.
  702.  
  703. =head1 OPTIONS
  704.  
  705. =over 5
  706.  
  707. =item B<-h> help
  708.  
  709. Prints out a brief help message.
  710.  
  711. =item B<-v> verbose
  712.  
  713. Describes search for the item in detail.
  714.  
  715. =item B<-t> text output
  716.  
  717. Display docs using plain text converter, instead of nroff. This may be faster,
  718. but it won't look as nice.
  719.  
  720. =item B<-u> unformatted
  721.  
  722. Find docs only; skip reformatting by pod2*
  723.  
  724. =item B<-m> module
  725.  
  726. Display the entire module: both code and unformatted pod documentation.
  727. This may be useful if the docs don't explain a function in the detail
  728. you need, and you'd like to inspect the code directly; perldoc will find
  729. the file for you and simply hand it off for display.
  730.  
  731. =item B<-l> file name only
  732.  
  733. Display the file name of the module found.
  734.  
  735. =item B<-F> file names
  736.  
  737. Consider arguments as file names, no search in directories will be performed.
  738.  
  739. =item B<-f> perlfunc
  740.  
  741. The B<-f> option followed by the name of a perl built in function will
  742. extract the documentation of this function from L<perlfunc>.
  743.  
  744. =item B<-q> perlfaq
  745.  
  746. The B<-q> option takes a regular expression as an argument.  It will search
  747. the question headings in perlfaq[1-9] and print the entries matching
  748. the regular expression.
  749.  
  750. =item B<-X> use an index if present
  751.  
  752. The B<-X> option looks for a entry whose basename matches the name given on the
  753. command line in the file C<$Config{archlib}/pod.idx>.  The pod.idx file should
  754. contain fully qualified filenames, one per line.
  755.  
  756. =item B<-U> run insecurely
  757.  
  758. Because B<perldoc> does not run properly tainted, and is known to
  759. have security issues, it will not normally execute as the superuser.
  760. If you use the B<-U> flag, it will do so, but only after setting
  761. the effective and real IDs to nobody's or nouser's account, or -2
  762. if unavailable.  If it cannot relinguish its privileges, it will not
  763. run.  
  764.  
  765. =item B<PageName|ModuleName|ProgramName>
  766.  
  767. The item you want to look up.  Nested modules (such as C<File::Basename>)
  768. are specified either as C<File::Basename> or C<File/Basename>.  You may also
  769. give a descriptive name of a page, such as C<perlfunc>. You may also give a
  770. partial or wrong-case name, such as "basename" for "File::Basename", but
  771. this will be slower, if there is more then one page with the same partial
  772. name, you will only get the first one.
  773.  
  774. =back
  775.  
  776. =head1 ENVIRONMENT
  777.  
  778. Any switches in the C<PERLDOC> environment variable will be used before the
  779. command line arguments.  C<perldoc> also searches directories
  780. specified by the C<PERL5LIB> (or C<PERLLIB> if C<PERL5LIB> is not
  781. defined) and C<PATH> environment variables.
  782. (The latter is so that embedded pods for executables, such as
  783. C<perldoc> itself, are available.)  C<perldoc> will use, in order of
  784. preference, the pager defined in C<PERLDOC_PAGER>, C<MANPAGER>, or
  785. C<PAGER> before trying to find a pager on its own.  (C<MANPAGER> is not
  786. used if C<perldoc> was told to display plain text or unformatted pod.)
  787.  
  788. One useful value for C<PERLDOC_PAGER> is C<less -+C -E>.
  789.  
  790. =head1 VERSION
  791.  
  792. This is perldoc v2.01.
  793.  
  794. =head1 AUTHOR
  795.  
  796. Kenneth Albanowski <kjahds@kjahds.com>
  797.  
  798. Minor updates by Andy Dougherty <doughera@lafcol.lafayette.edu>,
  799. and others.
  800.  
  801. =cut
  802.  
  803. #
  804. # Version 2.02: Mon Mar 13 18:03:04 MST 2000
  805. #       Tom Christiansen <tchrist@perl.com>
  806. #    Added -U insecurity option
  807. # Version 2.01: Sat Mar 11 15:22:33 MST 2000 
  808. #       Tom Christiansen <tchrist@perl.com>, querulously.
  809. #       Security and correctness patches.
  810. #       What a twisted bit of distasteful spaghetti code.
  811. # Version 2.0: ????
  812. # Version 1.15: Tue Aug 24 01:50:20 EST 1999
  813. #       Charles Wilson <cwilson@ece.gatech.edu>
  814. #    changed /pod/ directory to /pods/ for cygwin
  815. #         to support cygwin/win32
  816. # Version 1.14: Wed Jul 15 01:50:20 EST 1998
  817. #       Robin Barker <rmb1@cise.npl.co.uk>
  818. #    -strict, -w cleanups
  819. # Version 1.13: Fri Feb 27 16:20:50 EST 1997
  820. #       Gurusamy Sarathy <gsar@activestate.com>
  821. #    -doc tweaks for -F and -X options
  822. # Version 1.12: Sat Apr 12 22:41:09 EST 1997
  823. #       Gurusamy Sarathy <gsar@activestate.com>
  824. #    -various fixes for win32
  825. # Version 1.11: Tue Dec 26 09:54:33 EST 1995
  826. #       Kenneth Albanowski <kjahds@kjahds.com>
  827. #   -added Charles Bailey's further VMS patches, and -u switch
  828. #   -added -t switch, with pod2text support
  829. #
  830. # Version 1.10: Thu Nov  9 07:23:47 EST 1995
  831. #        Kenneth Albanowski <kjahds@kjahds.com>
  832. #    -added VMS support
  833. #    -added better error recognition (on no found pages, just exit. On
  834. #     missing nroff/pod2man, just display raw pod.)
  835. #    -added recursive/case-insensitive matching (thanks, Andreas). This
  836. #     slows things down a bit, unfortunately. Give a precise name, and
  837. #     it'll run faster.
  838. #
  839. # Version 1.01:    Tue May 30 14:47:34 EDT 1995
  840. #        Andy Dougherty  <doughera@lafcol.lafayette.edu>
  841. #   -added pod documentation.
  842. #   -added PATH searching.
  843. #   -added searching pod/ subdirectory (mainly to pick up perlfunc.pod
  844. #    and friends.
  845. #
  846. #
  847. # TODO:
  848. #
  849. #    Cache directories read during sloppy match
  850. !NO!SUBS!
  851.  
  852. close OUT or die "Can't close $file: $!";
  853. chmod 0755, $file or die "Can't reset permissions for $file: $!\n";
  854. exec("$Config{'eunicefix'} $file") if $Config{'eunicefix'} ne ':';
  855. chdir $origdir;
  856.