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