1898184e3Ssthenuse 5.006; # we use some open(X, "<", $y) syntax 2898184e3Ssthen 3898184e3Ssthenpackage Pod::Perldoc; 4898184e3Ssthenuse strict; 5898184e3Ssthenuse warnings; 6898184e3Ssthenuse Config '%Config'; 7898184e3Ssthen 8898184e3Ssthenuse Fcntl; # for sysopen 9898184e3Ssthenuse File::Basename qw(basename); 10898184e3Ssthenuse File::Spec::Functions qw(catfile catdir splitdir); 11898184e3Ssthen 12898184e3Ssthenuse vars qw($VERSION @Pagers $Bindir $Pod2man 13898184e3Ssthen $Temp_Files_Created $Temp_File_Lifetime 14898184e3Ssthen); 15*91f110e0Safresh1$VERSION = '3.19'; 16898184e3Ssthen 17898184e3Ssthen#.......................................................................... 18898184e3Ssthen 19898184e3SsthenBEGIN { # Make a DEBUG constant very first thing... 20898184e3Ssthen unless(defined &DEBUG) { 21898184e3Ssthen if(($ENV{'PERLDOCDEBUG'} || '') =~ m/^(\d+)/) { # untaint 22898184e3Ssthen eval("sub DEBUG () {$1}"); 23898184e3Ssthen die "WHAT? Couldn't eval-up a DEBUG constant!? $@" if $@; 24898184e3Ssthen } else { 25898184e3Ssthen *DEBUG = sub () {0}; 26898184e3Ssthen } 27898184e3Ssthen } 28898184e3Ssthen} 29898184e3Ssthen 30898184e3Ssthenuse Pod::Perldoc::GetOptsOO; # uses the DEBUG. 31898184e3Ssthenuse Carp qw(croak carp); 32898184e3Ssthen 33898184e3Ssthen# these are also in BaseTo, which I don't want to inherit 34898184e3Ssthensub debugging { 35898184e3Ssthen my $self = shift; 36898184e3Ssthen 37898184e3Ssthen ( defined(&Pod::Perldoc::DEBUG) and &Pod::Perldoc::DEBUG() ) 38898184e3Ssthen } 39898184e3Ssthen 40898184e3Ssthensub debug { 41898184e3Ssthen my( $self, @messages ) = @_; 42898184e3Ssthen return unless $self->debugging; 43898184e3Ssthen print STDERR map { "DEBUG : $_" } @messages; 44898184e3Ssthen } 45898184e3Ssthen 46898184e3Ssthensub warn { 47898184e3Ssthen my( $self, @messages ) = @_; 48898184e3Ssthen 49898184e3Ssthen carp( join "\n", @messages, '' ); 50898184e3Ssthen } 51898184e3Ssthen 52898184e3Ssthensub die { 53898184e3Ssthen my( $self, @messages ) = @_; 54898184e3Ssthen 55898184e3Ssthen croak( join "\n", @messages, '' ); 56898184e3Ssthen } 57898184e3Ssthen 58898184e3Ssthen#.......................................................................... 59898184e3Ssthen 60898184e3Ssthensub TRUE () {1} 61898184e3Ssthensub FALSE () {return} 62898184e3Ssthensub BE_LENIENT () {1} 63898184e3Ssthen 64898184e3SsthenBEGIN { 65898184e3Ssthen *is_vms = $^O eq 'VMS' ? \&TRUE : \&FALSE unless defined &is_vms; 66898184e3Ssthen *is_mswin32 = $^O eq 'MSWin32' ? \&TRUE : \&FALSE unless defined &is_mswin32; 67898184e3Ssthen *is_dos = $^O eq 'dos' ? \&TRUE : \&FALSE unless defined &is_dos; 68898184e3Ssthen *is_os2 = $^O eq 'os2' ? \&TRUE : \&FALSE unless defined &is_os2; 69898184e3Ssthen *is_cygwin = $^O eq 'cygwin' ? \&TRUE : \&FALSE unless defined &is_cygwin; 70898184e3Ssthen *is_linux = $^O eq 'linux' ? \&TRUE : \&FALSE unless defined &is_linux; 71898184e3Ssthen *is_hpux = $^O =~ m/hpux/ ? \&TRUE : \&FALSE unless defined &is_hpux; 72898184e3Ssthen} 73898184e3Ssthen 74898184e3Ssthen$Temp_File_Lifetime ||= 60 * 60 * 24 * 5; 75898184e3Ssthen # If it's older than five days, it's quite unlikely 76898184e3Ssthen # that anyone's still looking at it!! 77898184e3Ssthen # (Currently used only by the MSWin cleanup routine) 78898184e3Ssthen 79898184e3Ssthen 80898184e3Ssthen#.......................................................................... 81898184e3Ssthen{ my $pager = $Config{'pager'}; 82898184e3Ssthen push @Pagers, $pager if -x (split /\s+/, $pager)[0] or __PACKAGE__->is_vms; 83898184e3Ssthen} 84898184e3Ssthen$Bindir = $Config{'scriptdirexp'}; 85898184e3Ssthen$Pod2man = "pod2man" . ( $Config{'versiononly'} ? $Config{'version'} : '' ); 86898184e3Ssthen 87898184e3Ssthen# End of class-init stuff 88898184e3Ssthen# 89898184e3Ssthen########################################################################### 90898184e3Ssthen# 91898184e3Ssthen# Option accessors... 92898184e3Ssthen 93898184e3Ssthenforeach my $subname (map "opt_$_", split '', q{mhlDriFfXqnTdULv}) { 94898184e3Ssthen no strict 'refs'; 95898184e3Ssthen *$subname = do{ use strict 'refs'; sub () { shift->_elem($subname, @_) } }; 96898184e3Ssthen} 97898184e3Ssthen 98898184e3Ssthen# And these are so that GetOptsOO knows they take options: 99898184e3Ssthensub opt_f_with { shift->_elem('opt_f', @_) } 100898184e3Ssthensub opt_q_with { shift->_elem('opt_q', @_) } 101898184e3Ssthensub opt_d_with { shift->_elem('opt_d', @_) } 102898184e3Ssthensub opt_L_with { shift->_elem('opt_L', @_) } 103898184e3Ssthensub opt_v_with { shift->_elem('opt_v', @_) } 104898184e3Ssthen 105898184e3Ssthensub opt_w_with { # Specify an option for the formatter subclass 106898184e3Ssthen my($self, $value) = @_; 107898184e3Ssthen if($value =~ m/^([-_a-zA-Z][-_a-zA-Z0-9]*)(?:[=\:](.*?))?$/s) { 108898184e3Ssthen my $option = $1; 109898184e3Ssthen my $option_value = defined($2) ? $2 : "TRUE"; 110898184e3Ssthen $option =~ tr/\-/_/s; # tolerate "foo-bar" for "foo_bar" 111898184e3Ssthen $self->add_formatter_option( $option, $option_value ); 112898184e3Ssthen } else { 113898184e3Ssthen $self->warn( qq("$value" isn't a good formatter option name. I'm ignoring it!\n ) ); 114898184e3Ssthen } 115898184e3Ssthen return; 116898184e3Ssthen} 117898184e3Ssthen 118898184e3Ssthensub opt_M_with { # specify formatter class name(s) 119898184e3Ssthen my($self, $classes) = @_; 120898184e3Ssthen return unless defined $classes and length $classes; 121898184e3Ssthen DEBUG > 4 and print "Considering new formatter classes -M$classes\n"; 122898184e3Ssthen my @classes_to_add; 123898184e3Ssthen foreach my $classname (split m/[,;]+/s, $classes) { 124898184e3Ssthen next unless $classname =~ m/\S/; 125898184e3Ssthen if( $classname =~ m/^(\w+(::\w+)+)$/s ) { 126898184e3Ssthen # A mildly restrictive concept of what modulenames are valid. 127898184e3Ssthen push @classes_to_add, $1; # untaint 128898184e3Ssthen } else { 129898184e3Ssthen $self->warn( qq("$classname" isn't a valid classname. Ignoring.\n) ); 130898184e3Ssthen } 131898184e3Ssthen } 132898184e3Ssthen 133898184e3Ssthen unshift @{ $self->{'formatter_classes'} }, @classes_to_add; 134898184e3Ssthen 135898184e3Ssthen DEBUG > 3 and print( 136898184e3Ssthen "Adding @classes_to_add to the list of formatter classes, " 137898184e3Ssthen . "making them @{ $self->{'formatter_classes'} }.\n" 138898184e3Ssthen ); 139898184e3Ssthen 140898184e3Ssthen return; 141898184e3Ssthen} 142898184e3Ssthen 143898184e3Ssthensub opt_V { # report version and exit 144898184e3Ssthen print join '', 145898184e3Ssthen "Perldoc v$VERSION, under perl v$] for $^O", 146898184e3Ssthen 147898184e3Ssthen (defined(&Win32::BuildNumber) and defined &Win32::BuildNumber()) 148898184e3Ssthen ? (" (win32 build ", &Win32::BuildNumber(), ")") : (), 149898184e3Ssthen 150898184e3Ssthen (chr(65) eq 'A') ? () : " (non-ASCII)", 151898184e3Ssthen 152898184e3Ssthen "\n", 153898184e3Ssthen ; 154898184e3Ssthen exit; 155898184e3Ssthen} 156898184e3Ssthen 157898184e3Ssthensub opt_t { # choose plaintext as output format 158898184e3Ssthen my $self = shift; 159898184e3Ssthen $self->opt_o_with('text') if @_ and $_[0]; 160898184e3Ssthen return $self->_elem('opt_t', @_); 161898184e3Ssthen} 162898184e3Ssthen 163898184e3Ssthensub opt_u { # choose raw pod as output format 164898184e3Ssthen my $self = shift; 165898184e3Ssthen $self->opt_o_with('pod') if @_ and $_[0]; 166898184e3Ssthen return $self->_elem('opt_u', @_); 167898184e3Ssthen} 168898184e3Ssthen 169898184e3Ssthensub opt_n_with { 170898184e3Ssthen # choose man as the output format, and specify the proggy to run 171898184e3Ssthen my $self = shift; 172898184e3Ssthen $self->opt_o_with('man') if @_ and $_[0]; 173898184e3Ssthen $self->_elem('opt_n', @_); 174898184e3Ssthen} 175898184e3Ssthen 176898184e3Ssthensub opt_o_with { # "o" for output format 177898184e3Ssthen my($self, $rest) = @_; 178898184e3Ssthen return unless defined $rest and length $rest; 179898184e3Ssthen if($rest =~ m/^(\w+)$/s) { 180898184e3Ssthen $rest = $1; #untaint 181898184e3Ssthen } else { 182898184e3Ssthen $self->warn( qq("$rest" isn't a valid output format. Skipping.\n") ); 183898184e3Ssthen return; 184898184e3Ssthen } 185898184e3Ssthen 186898184e3Ssthen $self->aside("Noting \"$rest\" as desired output format...\n"); 187898184e3Ssthen 188898184e3Ssthen # Figure out what class(es) that could actually mean... 189898184e3Ssthen 190898184e3Ssthen my @classes; 191898184e3Ssthen foreach my $prefix ("Pod::Perldoc::To", "Pod::Simple::", "Pod::") { 192898184e3Ssthen # Messy but smart: 193898184e3Ssthen foreach my $stem ( 194898184e3Ssthen $rest, # Yes, try it first with the given capitalization 195898184e3Ssthen "\L$rest", "\L\u$rest", "\U$rest" # And then try variations 196898184e3Ssthen 197898184e3Ssthen ) { 198898184e3Ssthen $self->aside("Considering $prefix$stem\n"); 199898184e3Ssthen push @classes, $prefix . $stem; 200898184e3Ssthen } 201898184e3Ssthen 202898184e3Ssthen # Tidier, but misses too much: 203898184e3Ssthen #push @classes, $prefix . ucfirst(lc($rest)); 204898184e3Ssthen } 205898184e3Ssthen $self->opt_M_with( join ";", @classes ); 206898184e3Ssthen return; 207898184e3Ssthen} 208898184e3Ssthen 209898184e3Ssthen########################################################################### 210898184e3Ssthen# % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 211898184e3Ssthen 212898184e3Ssthensub run { # to be called by the "perldoc" executable 213898184e3Ssthen my $class = shift; 214898184e3Ssthen if(DEBUG > 3) { 215898184e3Ssthen print "Parameters to $class\->run:\n"; 216898184e3Ssthen my @x = @_; 217898184e3Ssthen while(@x) { 218898184e3Ssthen $x[1] = '<undef>' unless defined $x[1]; 219898184e3Ssthen $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY'; 220898184e3Ssthen print " [$x[0]] => [$x[1]]\n"; 221898184e3Ssthen splice @x,0,2; 222898184e3Ssthen } 223898184e3Ssthen print "\n"; 224898184e3Ssthen } 225898184e3Ssthen return $class -> new(@_) -> process() || 0; 226898184e3Ssthen} 227898184e3Ssthen 228898184e3Ssthen# % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 229898184e3Ssthen########################################################################### 230898184e3Ssthen 231898184e3Ssthensub new { # yeah, nothing fancy 232898184e3Ssthen my $class = shift; 233898184e3Ssthen my $new = bless {@_}, (ref($class) || $class); 234898184e3Ssthen DEBUG > 1 and print "New $class object $new\n"; 235898184e3Ssthen $new->init(); 236898184e3Ssthen $new; 237898184e3Ssthen} 238898184e3Ssthen 239898184e3Ssthen#.......................................................................... 240898184e3Ssthen 241898184e3Ssthensub aside { # If we're in -D or DEBUG mode, say this. 242898184e3Ssthen my $self = shift; 243898184e3Ssthen if( DEBUG or $self->opt_D ) { 244898184e3Ssthen my $out = join( '', 245898184e3Ssthen DEBUG ? do { 246898184e3Ssthen my $callsub = (caller(1))[3]; 247898184e3Ssthen my $package = quotemeta(__PACKAGE__ . '::'); 248898184e3Ssthen $callsub =~ s/^$package/'/os; 249898184e3Ssthen # the o is justified, as $package really won't change. 250898184e3Ssthen $callsub . ": "; 251898184e3Ssthen } : '', 252898184e3Ssthen @_, 253898184e3Ssthen ); 254898184e3Ssthen if(DEBUG) { print $out } else { print STDERR $out } 255898184e3Ssthen } 256898184e3Ssthen return; 257898184e3Ssthen} 258898184e3Ssthen 259898184e3Ssthen#.......................................................................... 260898184e3Ssthen 261898184e3Ssthensub usage { 262898184e3Ssthen my $self = shift; 263898184e3Ssthen $self->warn( "@_\n" ) if @_; 264898184e3Ssthen 265898184e3Ssthen # Erase evidence of previous errors (if any), so exit status is simple. 266898184e3Ssthen $! = 0; 267898184e3Ssthen 268898184e3Ssthen CORE::die( <<EOF ); 269898184e3Ssthenperldoc [options] PageName|ModuleName|ProgramName|URL... 270898184e3Ssthenperldoc [options] -f BuiltinFunction 271898184e3Ssthenperldoc [options] -q FAQRegex 272898184e3Ssthenperldoc [options] -v PerlVariable 273898184e3Ssthen 274898184e3SsthenOptions: 275898184e3Ssthen -h Display this help message 276898184e3Ssthen -V Report version 277898184e3Ssthen -r Recursive search (slow) 278898184e3Ssthen -i Ignore case 279898184e3Ssthen -t Display pod using pod2text instead of Pod::Man and groff 280898184e3Ssthen (-t is the default on win32 unless -n is specified) 281898184e3Ssthen -u Display unformatted pod text 282898184e3Ssthen -m Display module's file in its entirety 283898184e3Ssthen -n Specify replacement for groff 284898184e3Ssthen -l Display the module's file name 285898184e3Ssthen -F Arguments are file names, not modules 286898184e3Ssthen -D Verbosely describe what's going on 287898184e3Ssthen -T Send output to STDOUT without any pager 288898184e3Ssthen -d output_filename_to_send_to 289898184e3Ssthen -o output_format_name 290898184e3Ssthen -M FormatterModuleNameToUse 291898184e3Ssthen -w formatter_option:option_value 292898184e3Ssthen -L translation_code Choose doc translation (if any) 293898184e3Ssthen -X Use index if present (looks for pod.idx at $Config{archlib}) 294898184e3Ssthen -q Search the text of questions (not answers) in perlfaq[1-9] 295898184e3Ssthen -f Search Perl built-in functions 296898184e3Ssthen -v Search predefined Perl variables 297898184e3Ssthen 298898184e3SsthenPageName|ModuleName|ProgramName|URL... 299898184e3Ssthen is the name of a piece of documentation that you want to look at. You 300898184e3Ssthen may either give a descriptive name of the page (as in the case of 301898184e3Ssthen `perlfunc') the name of a module, either like `Term::Info' or like 302898184e3Ssthen `Term/Info', or the name of a program, like `perldoc', or a URL 303898184e3Ssthen starting with http(s). 304898184e3Ssthen 305898184e3SsthenBuiltinFunction 306898184e3Ssthen is the name of a perl function. Will extract documentation from 307898184e3Ssthen `perlfunc' or `perlop'. 308898184e3Ssthen 309898184e3SsthenFAQRegex 310898184e3Ssthen is a regex. Will search perlfaq[1-9] for and extract any 311898184e3Ssthen questions that match. 312898184e3Ssthen 313898184e3SsthenAny switches in the PERLDOC environment variable will be used before the 314898184e3Ssthencommand line arguments. The optional pod index file contains a list of 315898184e3Ssthenfilenames, one per line. 316898184e3Ssthen [Perldoc v$VERSION] 317898184e3SsthenEOF 318898184e3Ssthen 319898184e3Ssthen} 320898184e3Ssthen 321898184e3Ssthen#.......................................................................... 322898184e3Ssthen 323898184e3Ssthensub program_name { 324898184e3Ssthen my( $self ) = @_; 325898184e3Ssthen 326898184e3Ssthen if( my $link = readlink( $0 ) ) { 327898184e3Ssthen $self->debug( "The value in $0 is a symbolic link to $link\n" ); 328898184e3Ssthen } 329898184e3Ssthen 330898184e3Ssthen my $basename = basename( $0 ); 331898184e3Ssthen 332898184e3Ssthen $self->debug( "\$0 is [$0]\nbasename is [$basename]\n" ); 333898184e3Ssthen # possible name forms 334898184e3Ssthen # perldoc 335898184e3Ssthen # perldoc-v5.14 336898184e3Ssthen # perldoc-5.14 337898184e3Ssthen # perldoc-5.14.2 338898184e3Ssthen # perlvar # an alias mentioned in Camel 3 339898184e3Ssthen { 340898184e3Ssthen my( $untainted ) = $basename =~ m/( 341898184e3Ssthen \A 342898184e3Ssthen perl 343898184e3Ssthen (?: doc | func | faq | help | op | toc | var # Camel 3 344898184e3Ssthen ) 345898184e3Ssthen (?: -? v? \d+ \. \d+ (?:\. \d+)? )? # possible version 346898184e3Ssthen (?: \. (?: bat | exe | com ) )? # possible extension 347898184e3Ssthen \z 348898184e3Ssthen ) 349898184e3Ssthen /x; 350898184e3Ssthen 351898184e3Ssthen $self->debug($untainted); 352898184e3Ssthen return $untainted if $untainted; 353898184e3Ssthen } 354898184e3Ssthen 355898184e3Ssthen $self->warn(<<"HERE"); 356898184e3SsthenYou called the perldoc command with a name that I didn't recognize. 357898184e3SsthenThis might mean that someone is tricking you into running a 358898184e3Ssthenprogram you don't intend to use, but it also might mean that you 359898184e3Ssthencreated your own link to perldoc. I think your program name is 360898184e3Ssthen[$basename]. 361898184e3Ssthen 362898184e3SsthenI'll allow this if the filename only has [a-zA-Z0-9._-]. 363898184e3SsthenHERE 364898184e3Ssthen 365898184e3Ssthen { 366898184e3Ssthen my( $untainted ) = $basename =~ m/( 367898184e3Ssthen \A [a-zA-Z0-9._-]+ \z 368898184e3Ssthen )/x; 369898184e3Ssthen 370898184e3Ssthen $self->debug($untainted); 371898184e3Ssthen return $untainted if $untainted; 372898184e3Ssthen } 373898184e3Ssthen 374898184e3Ssthen $self->die(<<"HERE"); 375898184e3SsthenI think that your name for perldoc is potentially unsafe, so I'm 376898184e3Ssthengoing to disallow it. I'd rather you be safe than sorry. If you 377898184e3Ssthenintended to use the name I'm disallowing, please tell the maintainers 378898184e3Ssthenabout it. Write to: 379898184e3Ssthen 380898184e3Ssthen Pod-Perldoc\@rt.cpan.org 381898184e3Ssthen 382898184e3SsthenHERE 383898184e3Ssthen} 384898184e3Ssthen 385898184e3Ssthen#.......................................................................... 386898184e3Ssthen 387898184e3Ssthensub usage_brief { 388898184e3Ssthen my $self = shift; 389898184e3Ssthen my $program_name = $self->program_name; 390898184e3Ssthen 391898184e3Ssthen CORE::die( <<"EOUSAGE" ); 392898184e3SsthenUsage: $program_name [-hVriDtumFXlT] [-n nroffer_program] 393898184e3Ssthen [-d output_filename] [-o output_format] [-M FormatterModule] 394898184e3Ssthen [-w formatter_option:option_value] [-L translation_code] 395898184e3Ssthen PageName|ModuleName|ProgramName 396898184e3Ssthen 397898184e3SsthenExamples: 398898184e3Ssthen 399898184e3Ssthen $program_name -f PerlFunc 400898184e3Ssthen $program_name -q FAQKeywords 401898184e3Ssthen $program_name -v PerlVar 402898184e3Ssthen 403898184e3SsthenThe -h option prints more help. Also try "$program_name perldoc" to get 404898184e3Ssthenacquainted with the system. [Perldoc v$VERSION] 405898184e3SsthenEOUSAGE 406898184e3Ssthen 407898184e3Ssthen} 408898184e3Ssthen 409898184e3Ssthen#.......................................................................... 410898184e3Ssthen 411898184e3Ssthensub pagers { @{ shift->{'pagers'} } } 412898184e3Ssthen 413898184e3Ssthen#.......................................................................... 414898184e3Ssthen 415898184e3Ssthensub _elem { # handy scalar meta-accessor: shift->_elem("foo", @_) 416898184e3Ssthen if(@_ > 2) { return $_[0]{ $_[1] } = $_[2] } 417898184e3Ssthen else { return $_[0]{ $_[1] } } 418898184e3Ssthen} 419898184e3Ssthen#.......................................................................... 420898184e3Ssthen########################################################################### 421898184e3Ssthen# 422898184e3Ssthen# Init formatter switches, and start it off with __bindir and all that 423898184e3Ssthen# other stuff that ToMan.pm needs. 424898184e3Ssthen# 425898184e3Ssthen 426898184e3Ssthensub init { 427898184e3Ssthen my $self = shift; 428898184e3Ssthen 429898184e3Ssthen # Make sure creat()s are neither too much nor too little 430898184e3Ssthen eval { umask(0077) }; # doubtless someone has no mask 431898184e3Ssthen 432898184e3Ssthen $self->{'args'} ||= \@ARGV; 433898184e3Ssthen $self->{'found'} ||= []; 434898184e3Ssthen $self->{'temp_file_list'} ||= []; 435898184e3Ssthen 436898184e3Ssthen 437898184e3Ssthen $self->{'target'} = undef; 438898184e3Ssthen 439898184e3Ssthen $self->init_formatter_class_list; 440898184e3Ssthen 441898184e3Ssthen $self->{'pagers' } = [@Pagers] unless exists $self->{'pagers'}; 442898184e3Ssthen $self->{'bindir' } = $Bindir unless exists $self->{'bindir'}; 443898184e3Ssthen $self->{'pod2man'} = $Pod2man unless exists $self->{'pod2man'}; 444898184e3Ssthen 445898184e3Ssthen push @{ $self->{'formatter_switches'} = [] }, ( 446898184e3Ssthen # Yeah, we could use a hashref, but maybe there's some class where options 447898184e3Ssthen # have to be ordered; so we'll use an arrayref. 448898184e3Ssthen 449898184e3Ssthen [ '__bindir' => $self->{'bindir' } ], 450898184e3Ssthen [ '__pod2man' => $self->{'pod2man'} ], 451898184e3Ssthen ); 452898184e3Ssthen 453898184e3Ssthen DEBUG > 3 and printf "Formatter switches now: [%s]\n", 454898184e3Ssthen join ' ', map "[@$_]", @{ $self->{'formatter_switches'} }; 455898184e3Ssthen 456898184e3Ssthen $self->{'translators'} = []; 457898184e3Ssthen $self->{'extra_search_dirs'} = []; 458898184e3Ssthen 459898184e3Ssthen return; 460898184e3Ssthen} 461898184e3Ssthen 462898184e3Ssthen#.......................................................................... 463898184e3Ssthen 464898184e3Ssthensub init_formatter_class_list { 465898184e3Ssthen my $self = shift; 466898184e3Ssthen $self->{'formatter_classes'} ||= []; 467898184e3Ssthen 468898184e3Ssthen # Remember, no switches have been read yet, when 469898184e3Ssthen # we've started this routine. 470898184e3Ssthen 471898184e3Ssthen $self->opt_M_with('Pod::Perldoc::ToPod'); # the always-there fallthru 472898184e3Ssthen $self->opt_o_with('text'); 473898184e3Ssthen $self->opt_o_with('man') unless $self->is_mswin32 || $self->is_dos 474898184e3Ssthen || !($ENV{TERM} && ( 475898184e3Ssthen ($ENV{TERM} || '') !~ /dumb|emacs|none|unknown/i 476898184e3Ssthen )); 477898184e3Ssthen 478898184e3Ssthen return; 479898184e3Ssthen} 480898184e3Ssthen 481898184e3Ssthen#.......................................................................... 482898184e3Ssthen 483898184e3Ssthensub process { 484898184e3Ssthen # if this ever returns, its retval will be used for exit(RETVAL) 485898184e3Ssthen 486898184e3Ssthen my $self = shift; 487898184e3Ssthen DEBUG > 1 and print " Beginning process.\n"; 488898184e3Ssthen DEBUG > 1 and print " Args: @{$self->{'args'}}\n\n"; 489898184e3Ssthen if(DEBUG > 3) { 490898184e3Ssthen print "Object contents:\n"; 491898184e3Ssthen my @x = %$self; 492898184e3Ssthen while(@x) { 493898184e3Ssthen $x[1] = '<undef>' unless defined $x[1]; 494898184e3Ssthen $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY'; 495898184e3Ssthen print " [$x[0]] => [$x[1]]\n"; 496898184e3Ssthen splice @x,0,2; 497898184e3Ssthen } 498898184e3Ssthen print "\n"; 499898184e3Ssthen } 500898184e3Ssthen 501898184e3Ssthen # TODO: make it deal with being invoked as various different things 502898184e3Ssthen # such as perlfaq". 503898184e3Ssthen 504898184e3Ssthen return $self->usage_brief unless @{ $self->{'args'} }; 505898184e3Ssthen $self->pagers_guessing; 506898184e3Ssthen $self->options_reading; 507898184e3Ssthen $self->aside(sprintf "$0 => %s v%s\n", ref($self), $self->VERSION); 508898184e3Ssthen $self->drop_privs_maybe; 509898184e3Ssthen $self->options_processing; 510898184e3Ssthen 511898184e3Ssthen # Hm, we have @pages and @found, but we only really act on one 512898184e3Ssthen # file per call, with the exception of the opt_q hack, and with 513898184e3Ssthen # -l things 514898184e3Ssthen 515898184e3Ssthen $self->aside("\n"); 516898184e3Ssthen 517898184e3Ssthen my @pages; 518898184e3Ssthen $self->{'pages'} = \@pages; 519898184e3Ssthen if( $self->opt_f) { @pages = qw(perlfunc perlop) } 520898184e3Ssthen elsif( $self->opt_q) { @pages = ("perlfaq1" .. "perlfaq9") } 521898184e3Ssthen elsif( $self->opt_v) { @pages = ("perlvar") } 522898184e3Ssthen else { @pages = @{$self->{'args'}}; 523898184e3Ssthen # @pages = __FILE__ 524898184e3Ssthen # if @pages == 1 and $pages[0] eq 'perldoc'; 525898184e3Ssthen } 526898184e3Ssthen 527898184e3Ssthen return $self->usage_brief unless @pages; 528898184e3Ssthen 529898184e3Ssthen $self->find_good_formatter_class(); 530898184e3Ssthen $self->formatter_sanity_check(); 531898184e3Ssthen 532898184e3Ssthen $self->maybe_diddle_INC(); 533898184e3Ssthen # for when we're apparently in a module or extension directory 534898184e3Ssthen 535898184e3Ssthen my @found = $self->grand_search_init(\@pages); 536898184e3Ssthen exit ($self->is_vms ? 98962 : 1) unless @found; 537898184e3Ssthen 538898184e3Ssthen if ($self->opt_l and not $self->opt_q ) { 539898184e3Ssthen DEBUG and print "We're in -l mode, so byebye after this:\n"; 540898184e3Ssthen print join("\n", @found), "\n"; 541898184e3Ssthen return; 542898184e3Ssthen } 543898184e3Ssthen 544898184e3Ssthen $self->tweak_found_pathnames(\@found); 545898184e3Ssthen $self->assert_closing_stdout; 546898184e3Ssthen return $self->page_module_file(@found) if $self->opt_m; 547898184e3Ssthen DEBUG > 2 and print "Found: [@found]\n"; 548898184e3Ssthen 549898184e3Ssthen return $self->render_and_page(\@found); 550898184e3Ssthen} 551898184e3Ssthen 552898184e3Ssthen#.......................................................................... 553898184e3Ssthen{ 554898184e3Ssthen 555898184e3Ssthenmy( %class_seen, %class_loaded ); 556898184e3Ssthensub find_good_formatter_class { 557898184e3Ssthen my $self = $_[0]; 558898184e3Ssthen my @class_list = @{ $self->{'formatter_classes'} || [] }; 559898184e3Ssthen $self->die( "WHAT? Nothing in the formatter class list!?" ) unless @class_list; 560898184e3Ssthen 561898184e3Ssthen my $good_class_found; 562898184e3Ssthen foreach my $c (@class_list) { 563898184e3Ssthen DEBUG > 4 and print "Trying to load $c...\n"; 564898184e3Ssthen if($class_loaded{$c}) { 565898184e3Ssthen DEBUG > 4 and print "OK, the already-loaded $c it is!\n"; 566898184e3Ssthen $good_class_found = $c; 567898184e3Ssthen last; 568898184e3Ssthen } 569898184e3Ssthen 570898184e3Ssthen if($class_seen{$c}) { 571898184e3Ssthen DEBUG > 4 and print 572898184e3Ssthen "I've tried $c before, and it's no good. Skipping.\n"; 573898184e3Ssthen next; 574898184e3Ssthen } 575898184e3Ssthen 576898184e3Ssthen $class_seen{$c} = 1; 577898184e3Ssthen 578898184e3Ssthen if( $c->can('parse_from_file') ) { 579898184e3Ssthen DEBUG > 4 and print 580898184e3Ssthen "Interesting, the formatter class $c is already loaded!\n"; 581898184e3Ssthen 582898184e3Ssthen } elsif( 583898184e3Ssthen ( $self->is_os2 or $self->is_mswin32 or $self->is_dos or $self->is_os2) 584898184e3Ssthen # the always case-insensitive filesystems 585898184e3Ssthen and $class_seen{lc("~$c")}++ 586898184e3Ssthen ) { 587898184e3Ssthen DEBUG > 4 and print 588898184e3Ssthen "We already used something quite like \"\L$c\E\", so no point using $c\n"; 589898184e3Ssthen # This avoids redefining the package. 590898184e3Ssthen } else { 591898184e3Ssthen DEBUG > 4 and print "Trying to eval 'require $c'...\n"; 592898184e3Ssthen 593898184e3Ssthen local $^W = $^W; 594898184e3Ssthen if(DEBUG() or $self->opt_D) { 595898184e3Ssthen # feh, let 'em see it 596898184e3Ssthen } else { 597898184e3Ssthen $^W = 0; 598898184e3Ssthen # The average user just has no reason to be seeing 599898184e3Ssthen # $^W-suppressible warnings from the the require! 600898184e3Ssthen } 601898184e3Ssthen 602898184e3Ssthen eval "require $c"; 603898184e3Ssthen if($@) { 604898184e3Ssthen DEBUG > 4 and print "Couldn't load $c: $!\n"; 605898184e3Ssthen next; 606898184e3Ssthen } 607898184e3Ssthen } 608898184e3Ssthen 609898184e3Ssthen if( $c->can('parse_from_file') ) { 610898184e3Ssthen DEBUG > 4 and print "Settling on $c\n"; 611898184e3Ssthen my $v = $c->VERSION; 612898184e3Ssthen $v = ( defined $v and length $v ) ? " version $v" : ''; 613898184e3Ssthen $self->aside("Formatter class $c$v successfully loaded!\n"); 614898184e3Ssthen $good_class_found = $c; 615898184e3Ssthen last; 616898184e3Ssthen } else { 617898184e3Ssthen DEBUG > 4 and print "Class $c isn't a formatter?! Skipping.\n"; 618898184e3Ssthen } 619898184e3Ssthen } 620898184e3Ssthen 621898184e3Ssthen $self->die( "Can't find any loadable formatter class in @class_list?!\nAborting" ) 622898184e3Ssthen unless $good_class_found; 623898184e3Ssthen 624898184e3Ssthen $self->{'formatter_class'} = $good_class_found; 625898184e3Ssthen $self->aside("Will format with the class $good_class_found\n"); 626898184e3Ssthen 627898184e3Ssthen return; 628898184e3Ssthen} 629898184e3Ssthen 630898184e3Ssthen} 631898184e3Ssthen#.......................................................................... 632898184e3Ssthen 633898184e3Ssthensub formatter_sanity_check { 634898184e3Ssthen my $self = shift; 635898184e3Ssthen my $formatter_class = $self->{'formatter_class'} 636898184e3Ssthen || $self->die( "NO FORMATTER CLASS YET!?" ); 637898184e3Ssthen 638898184e3Ssthen if(!$self->opt_T # so -T can FORCE sending to STDOUT 639898184e3Ssthen and $formatter_class->can('is_pageable') 640898184e3Ssthen and !$formatter_class->is_pageable 641898184e3Ssthen and !$formatter_class->can('page_for_perldoc') 642898184e3Ssthen ) { 643898184e3Ssthen my $ext = 644898184e3Ssthen ($formatter_class->can('output_extension') 645898184e3Ssthen && $formatter_class->output_extension 646898184e3Ssthen ) || ''; 647898184e3Ssthen $ext = ".$ext" if length $ext; 648898184e3Ssthen 649898184e3Ssthen my $me = $self->program_name; 650898184e3Ssthen $self->die( 651898184e3Ssthen "When using Perldoc to format with $formatter_class, you have to\n" 652898184e3Ssthen . "specify -T or -dsomefile$ext\n" 653898184e3Ssthen . "See `$me perldoc' for more information on those switches.\n" ) 654898184e3Ssthen ; 655898184e3Ssthen } 656898184e3Ssthen} 657898184e3Ssthen 658898184e3Ssthen#.......................................................................... 659898184e3Ssthen 660898184e3Ssthensub render_and_page { 661898184e3Ssthen my($self, $found_list) = @_; 662898184e3Ssthen 663898184e3Ssthen $self->maybe_generate_dynamic_pod($found_list); 664898184e3Ssthen 665898184e3Ssthen my($out, $formatter) = $self->render_findings($found_list); 666898184e3Ssthen 667898184e3Ssthen if($self->opt_d) { 668898184e3Ssthen printf "Perldoc (%s) output saved to %s\n", 669898184e3Ssthen $self->{'formatter_class'} || ref($self), 670898184e3Ssthen $out; 671898184e3Ssthen print "But notice that it's 0 bytes long!\n" unless -s $out; 672898184e3Ssthen 673898184e3Ssthen 674898184e3Ssthen } elsif( # Allow the formatter to "page" itself, if it wants. 675898184e3Ssthen $formatter->can('page_for_perldoc') 676898184e3Ssthen and do { 677898184e3Ssthen $self->aside("Going to call $formatter\->page_for_perldoc(\"$out\")\n"); 678898184e3Ssthen if( $formatter->page_for_perldoc($out, $self) ) { 679898184e3Ssthen $self->aside("page_for_perldoc returned true, so NOT paging with $self.\n"); 680898184e3Ssthen 1; 681898184e3Ssthen } else { 682898184e3Ssthen $self->aside("page_for_perldoc returned false, so paging with $self instead.\n"); 683898184e3Ssthen ''; 684898184e3Ssthen } 685898184e3Ssthen } 686898184e3Ssthen ) { 687898184e3Ssthen # Do nothing, since the formatter has "paged" it for itself. 688898184e3Ssthen 689898184e3Ssthen } else { 690898184e3Ssthen # Page it normally (internally) 691898184e3Ssthen 692898184e3Ssthen if( -s $out ) { # Usual case: 693898184e3Ssthen $self->page($out, $self->{'output_to_stdout'}, $self->pagers); 694898184e3Ssthen 695898184e3Ssthen } else { 696898184e3Ssthen # Odd case: 697898184e3Ssthen $self->aside("Skipping $out (from $$found_list[0] " 698898184e3Ssthen . "via $$self{'formatter_class'}) as it is 0-length.\n"); 699898184e3Ssthen 700898184e3Ssthen push @{ $self->{'temp_file_list'} }, $out; 701898184e3Ssthen $self->unlink_if_temp_file($out); 702898184e3Ssthen } 703898184e3Ssthen } 704898184e3Ssthen 705898184e3Ssthen $self->after_rendering(); # any extra cleanup or whatever 706898184e3Ssthen 707898184e3Ssthen return; 708898184e3Ssthen} 709898184e3Ssthen 710898184e3Ssthen#.......................................................................... 711898184e3Ssthen 712898184e3Ssthensub options_reading { 713898184e3Ssthen my $self = shift; 714898184e3Ssthen 715898184e3Ssthen if( defined $ENV{"PERLDOC"} and length $ENV{"PERLDOC"} ) { 716898184e3Ssthen require Text::ParseWords; 717898184e3Ssthen $self->aside("Noting env PERLDOC setting of $ENV{'PERLDOC'}\n"); 718898184e3Ssthen # Yes, appends to the beginning 719898184e3Ssthen unshift @{ $self->{'args'} }, 720898184e3Ssthen Text::ParseWords::shellwords( $ENV{"PERLDOC"} ) 721898184e3Ssthen ; 722898184e3Ssthen DEBUG > 1 and print " Args now: @{$self->{'args'}}\n\n"; 723898184e3Ssthen } else { 724898184e3Ssthen DEBUG > 1 and print " Okay, no PERLDOC setting in ENV.\n"; 725898184e3Ssthen } 726898184e3Ssthen 727898184e3Ssthen DEBUG > 1 728898184e3Ssthen and print " Args right before switch processing: @{$self->{'args'}}\n"; 729898184e3Ssthen 730898184e3Ssthen Pod::Perldoc::GetOptsOO::getopts( $self, $self->{'args'}, 'YES' ) 731898184e3Ssthen or return $self->usage; 732898184e3Ssthen 733898184e3Ssthen DEBUG > 1 734898184e3Ssthen and print " Args after switch processing: @{$self->{'args'}}\n"; 735898184e3Ssthen 736898184e3Ssthen return $self->usage if $self->opt_h; 737898184e3Ssthen 738898184e3Ssthen return; 739898184e3Ssthen} 740898184e3Ssthen 741898184e3Ssthen#.......................................................................... 742898184e3Ssthen 743898184e3Ssthensub options_processing { 744898184e3Ssthen my $self = shift; 745898184e3Ssthen 746898184e3Ssthen if ($self->opt_X) { 747898184e3Ssthen my $podidx = "$Config{'archlib'}/pod.idx"; 748898184e3Ssthen $podidx = "" unless -f $podidx && -r _ && -M _ <= 7; 749898184e3Ssthen $self->{'podidx'} = $podidx; 750898184e3Ssthen } 751898184e3Ssthen 752898184e3Ssthen $self->{'output_to_stdout'} = 1 if $self->opt_T or ! -t STDOUT; 753898184e3Ssthen 754898184e3Ssthen $self->options_sanity; 755898184e3Ssthen 756898184e3Ssthen # This used to set a default, but that's now moved into any 757898184e3Ssthen # formatter that cares to have a default. 758898184e3Ssthen if( $self->opt_n ) { 759898184e3Ssthen $self->add_formatter_option( '__nroffer' => $self->opt_n ); 760898184e3Ssthen } 761898184e3Ssthen 762898184e3Ssthen # Get language from PERLDOC_POD2 environment variable 763898184e3Ssthen if ( ! $self->opt_L && $ENV{PERLDOC_POD2} ) { 764898184e3Ssthen if ( $ENV{PERLDOC_POD2} eq '1' ) { 765898184e3Ssthen $self->_elem('opt_L',(split(/\_/, $ENV{LC_ALL} || $ENV{LC_LANG} || $ENV{LANG}))[0] ); 766898184e3Ssthen } 767898184e3Ssthen else { 768898184e3Ssthen $self->_elem('opt_L', $ENV{PERLDOC_POD2}); 769898184e3Ssthen } 770898184e3Ssthen }; 771898184e3Ssthen 772898184e3Ssthen # Adjust for using translation packages 773898184e3Ssthen $self->add_translator(split(/\s+/,$self->opt_L)) if $self->opt_L; 774898184e3Ssthen 775898184e3Ssthen return; 776898184e3Ssthen} 777898184e3Ssthen 778898184e3Ssthen#.......................................................................... 779898184e3Ssthen 780898184e3Ssthensub options_sanity { 781898184e3Ssthen my $self = shift; 782898184e3Ssthen 783898184e3Ssthen # The opts-counting stuff interacts quite badly with 784898184e3Ssthen # the $ENV{"PERLDOC"} stuff. I.e., if I have $ENV{"PERLDOC"} 785898184e3Ssthen # set to -t, and I specify -u on the command line, I don't want 786898184e3Ssthen # to be hectored at that -u and -t don't make sense together. 787898184e3Ssthen 788898184e3Ssthen #my $opts = grep $_ && 1, # yes, the count of the set ones 789898184e3Ssthen # $self->opt_t, $self->opt_u, $self->opt_m, $self->opt_l 790898184e3Ssthen #; 791898184e3Ssthen # 792898184e3Ssthen #$self->usage("only one of -t, -u, -m or -l") if $opts > 1; 793898184e3Ssthen 794898184e3Ssthen 795898184e3Ssthen # Any sanity-checking need doing here? 796898184e3Ssthen 797898184e3Ssthen # But does not make sense to set either -f or -q in $ENV{"PERLDOC"} 798898184e3Ssthen if( $self->opt_f or $self->opt_q ) { 799898184e3Ssthen $self->usage("Only one of -f -or -q") if $self->opt_f and $self->opt_q; 800898184e3Ssthen $self->warn( 801*91f110e0Safresh1 "Perldoc is meant for reading one file at a time.\n", 802898184e3Ssthen "So these parameters are being ignored: ", 803898184e3Ssthen join(' ', @{$self->{'args'}}), 804898184e3Ssthen "\n" ) 805898184e3Ssthen if @{$self->{'args'}} 806898184e3Ssthen } 807898184e3Ssthen return; 808898184e3Ssthen} 809898184e3Ssthen 810898184e3Ssthen#.......................................................................... 811898184e3Ssthen 812898184e3Ssthensub grand_search_init { 813898184e3Ssthen my($self, $pages, @found) = @_; 814898184e3Ssthen 815898184e3Ssthen foreach (@$pages) { 816898184e3Ssthen if (/^http(s)?:\/\//) { 817898184e3Ssthen require HTTP::Tiny; 818898184e3Ssthen require File::Temp; 819898184e3Ssthen my $response = HTTP::Tiny->new->get($_); 820898184e3Ssthen if ($response->{success}) { 821898184e3Ssthen my ($fh, $filename) = File::Temp::tempfile(UNLINK => 1); 822898184e3Ssthen $fh->print($response->{content}); 823898184e3Ssthen push @found, $filename; 824898184e3Ssthen ($self->{podnames}{$filename} = 825898184e3Ssthen m{.*/([^/#?]+)} ? uc $1 : "UNKNOWN") 826898184e3Ssthen =~ s/\.P(?:[ML]|OD)\z//; 827898184e3Ssthen } 828898184e3Ssthen else { 829898184e3Ssthen print STDERR "No " . 830898184e3Ssthen ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n"; 831898184e3Ssthen } 832898184e3Ssthen next; 833898184e3Ssthen } 834898184e3Ssthen if ($self->{'podidx'} && open(PODIDX, $self->{'podidx'})) { 835898184e3Ssthen my $searchfor = catfile split '::', $_; 836898184e3Ssthen $self->aside( "Searching for '$searchfor' in $self->{'podidx'}\n" ); 837898184e3Ssthen local $_; 838898184e3Ssthen while (<PODIDX>) { 839898184e3Ssthen chomp; 840898184e3Ssthen push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?\z,i; 841898184e3Ssthen } 842898184e3Ssthen close(PODIDX) or $self->die( "Can't close $$self{'podidx'}: $!" ); 843898184e3Ssthen next; 844898184e3Ssthen } 845898184e3Ssthen 846898184e3Ssthen $self->aside( "Searching for $_\n" ); 847898184e3Ssthen 848898184e3Ssthen if ($self->opt_F) { 849898184e3Ssthen next unless -r; 850898184e3Ssthen push @found, $_ if $self->opt_l or $self->opt_m or $self->containspod($_); 851898184e3Ssthen next; 852898184e3Ssthen } 853898184e3Ssthen 854898184e3Ssthen my @searchdirs; 855898184e3Ssthen 856898184e3Ssthen # prepend extra search directories (including language specific) 857898184e3Ssthen push @searchdirs, @{ $self->{'extra_search_dirs'} }; 858898184e3Ssthen 859898184e3Ssthen # We must look both in @INC for library modules and in $bindir 860898184e3Ssthen # for executables, like h2xs or perldoc itself. 861898184e3Ssthen push @searchdirs, ($self->{'bindir'}, @INC); 862898184e3Ssthen unless ($self->opt_m) { 863898184e3Ssthen if ($self->is_vms) { 864898184e3Ssthen my($i,$trn); 865898184e3Ssthen for ($i = 0; $trn = $ENV{'DCL$PATH;'.$i}; $i++) { 866898184e3Ssthen push(@searchdirs,$trn); 867898184e3Ssthen } 868898184e3Ssthen push(@searchdirs,'perl_root:[lib.pods]') # installed pods 869898184e3Ssthen } 870898184e3Ssthen else { 871898184e3Ssthen push(@searchdirs, grep(-d, split($Config{path_sep}, 872898184e3Ssthen $ENV{'PATH'}))); 873898184e3Ssthen } 874898184e3Ssthen } 875898184e3Ssthen my @files = $self->searchfor(0,$_,@searchdirs); 876898184e3Ssthen if (@files) { 877898184e3Ssthen $self->aside( "Found as @files\n" ); 878898184e3Ssthen } 879898184e3Ssthen # add "perl" prefix, so "perldoc foo" may find perlfoo.pod 880898184e3Ssthen elsif (BE_LENIENT and !/\W/ and @files = $self->searchfor(0, "perl$_", @searchdirs)) { 881898184e3Ssthen $self->aside( "Loosely found as @files\n" ); 882898184e3Ssthen } 883898184e3Ssthen else { 884898184e3Ssthen # no match, try recursive search 885898184e3Ssthen @searchdirs = grep(!/^\.\z/s,@INC); 886898184e3Ssthen @files= $self->searchfor(1,$_,@searchdirs) if $self->opt_r; 887898184e3Ssthen if (@files) { 888898184e3Ssthen $self->aside( "Loosely found as @files\n" ); 889898184e3Ssthen } 890898184e3Ssthen else { 891898184e3Ssthen print STDERR "No " . 892898184e3Ssthen ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n"; 893898184e3Ssthen if ( @{ $self->{'found'} } ) { 894898184e3Ssthen print STDERR "However, try\n"; 895898184e3Ssthen my $me = $self->program_name; 896898184e3Ssthen for my $dir (@{ $self->{'found'} }) { 897898184e3Ssthen opendir(DIR, $dir) or $self->die( "opendir $dir: $!" ); 898898184e3Ssthen while (my $file = readdir(DIR)) { 899898184e3Ssthen next if ($file =~ /^\./s); 900898184e3Ssthen $file =~ s/\.(pm|pod)\z//; # XXX: badfs 901898184e3Ssthen print STDERR "\t$me $_\::$file\n"; 902898184e3Ssthen } 903898184e3Ssthen closedir(DIR) or $self->die( "closedir $dir: $!" ); 904898184e3Ssthen } 905898184e3Ssthen } 906898184e3Ssthen } 907898184e3Ssthen } 908898184e3Ssthen push(@found,@files); 909898184e3Ssthen } 910898184e3Ssthen return @found; 911898184e3Ssthen} 912898184e3Ssthen 913898184e3Ssthen#.......................................................................... 914898184e3Ssthen 915898184e3Ssthensub maybe_generate_dynamic_pod { 916898184e3Ssthen my($self, $found_things) = @_; 917898184e3Ssthen my @dynamic_pod; 918898184e3Ssthen 919898184e3Ssthen $self->search_perlfunc($found_things, \@dynamic_pod) if $self->opt_f; 920898184e3Ssthen 921898184e3Ssthen $self->search_perlvar($found_things, \@dynamic_pod) if $self->opt_v; 922898184e3Ssthen 923898184e3Ssthen $self->search_perlfaqs($found_things, \@dynamic_pod) if $self->opt_q; 924898184e3Ssthen 925898184e3Ssthen if( ! $self->opt_f and ! $self->opt_q and ! $self->opt_v ) { 926898184e3Ssthen DEBUG > 4 and print "That's a non-dynamic pod search.\n"; 927898184e3Ssthen } elsif ( @dynamic_pod ) { 928898184e3Ssthen $self->aside("Hm, I found some Pod from that search!\n"); 929898184e3Ssthen my ($buffd, $buffer) = $self->new_tempfile('pod', 'dyn'); 930898184e3Ssthen 931898184e3Ssthen push @{ $self->{'temp_file_list'} }, $buffer; 932898184e3Ssthen # I.e., it MIGHT be deleted at the end. 933898184e3Ssthen 934898184e3Ssthen my $in_list = !$self->not_dynamic && $self->opt_f || $self->opt_v; 935898184e3Ssthen 936898184e3Ssthen print $buffd "=over 8\n\n" if $in_list; 937898184e3Ssthen print $buffd @dynamic_pod or $self->die( "Can't print $buffer: $!" ); 938898184e3Ssthen print $buffd "=back\n" if $in_list; 939898184e3Ssthen 940898184e3Ssthen close $buffd or $self->die( "Can't close $buffer: $!" ); 941898184e3Ssthen 942898184e3Ssthen @$found_things = $buffer; 943898184e3Ssthen # Yes, so found_things never has more than one thing in 944898184e3Ssthen # it, by time we leave here 945898184e3Ssthen 946898184e3Ssthen $self->add_formatter_option('__filter_nroff' => 1); 947898184e3Ssthen 948898184e3Ssthen } else { 949898184e3Ssthen @$found_things = (); 950898184e3Ssthen $self->aside("I found no Pod from that search!\n"); 951898184e3Ssthen } 952898184e3Ssthen 953898184e3Ssthen return; 954898184e3Ssthen} 955898184e3Ssthen 956898184e3Ssthen#.......................................................................... 957898184e3Ssthen 958898184e3Ssthensub not_dynamic { 959898184e3Ssthen my ($self,$value) = @_; 960898184e3Ssthen $self->{__not_dynamic} = $value if @_ == 2; 961898184e3Ssthen return $self->{__not_dynamic}; 962898184e3Ssthen} 963898184e3Ssthen 964898184e3Ssthen#.......................................................................... 965898184e3Ssthen 966898184e3Ssthensub add_formatter_option { # $self->add_formatter_option('key' => 'value'); 967898184e3Ssthen my $self = shift; 968898184e3Ssthen push @{ $self->{'formatter_switches'} }, [ @_ ] if @_; 969898184e3Ssthen 970898184e3Ssthen DEBUG > 3 and printf "Formatter switches now: [%s]\n", 971898184e3Ssthen join ' ', map "[@$_]", @{ $self->{'formatter_switches'} }; 972898184e3Ssthen 973898184e3Ssthen return; 974898184e3Ssthen} 975898184e3Ssthen 976898184e3Ssthen#......................................................................... 977898184e3Ssthen 978898184e3Ssthensub new_translator { # $tr = $self->new_translator($lang); 979898184e3Ssthen my $self = shift; 980898184e3Ssthen my $lang = shift; 981898184e3Ssthen 982898184e3Ssthen my $pack = 'POD2::' . uc($lang); 983898184e3Ssthen eval "require $pack"; 984898184e3Ssthen if ( !$@ && $pack->can('new') ) { 985898184e3Ssthen return $pack->new(); 986898184e3Ssthen } 987898184e3Ssthen 988898184e3Ssthen eval { require POD2::Base }; 989898184e3Ssthen return if $@; 990898184e3Ssthen 991898184e3Ssthen return POD2::Base->new({ lang => $lang }); 992898184e3Ssthen} 993898184e3Ssthen 994898184e3Ssthen#......................................................................... 995898184e3Ssthen 996898184e3Ssthensub add_translator { # $self->add_translator($lang); 997898184e3Ssthen my $self = shift; 998898184e3Ssthen for my $lang (@_) { 999898184e3Ssthen my $tr = $self->new_translator($lang); 1000898184e3Ssthen if ( defined $tr ) { 1001898184e3Ssthen push @{ $self->{'translators'} }, $tr; 1002898184e3Ssthen push @{ $self->{'extra_search_dirs'} }, $tr->pod_dirs; 1003898184e3Ssthen 1004898184e3Ssthen $self->aside( "translator for '$lang' loaded\n" ); 1005898184e3Ssthen } else { 1006898184e3Ssthen # non-installed or bad translator package 1007898184e3Ssthen $self->warn( "Perldoc cannot load translator package for '$lang': ignored\n" ); 1008898184e3Ssthen } 1009898184e3Ssthen 1010898184e3Ssthen } 1011898184e3Ssthen return; 1012898184e3Ssthen} 1013898184e3Ssthen 1014898184e3Ssthen#.......................................................................... 1015898184e3Ssthen 1016898184e3Ssthensub search_perlvar { 1017898184e3Ssthen my($self, $found_things, $pod) = @_; 1018898184e3Ssthen 1019898184e3Ssthen my $opt = $self->opt_v; 1020898184e3Ssthen 1021898184e3Ssthen if ( $opt !~ /^ (?: [\@\%\$]\S+ | [A-Z]\w* ) $/x ) { 1022898184e3Ssthen CORE::die( "'$opt' does not look like a Perl variable\n" ); 1023898184e3Ssthen } 1024898184e3Ssthen 1025898184e3Ssthen DEBUG > 2 and print "Search: @$found_things\n"; 1026898184e3Ssthen 1027898184e3Ssthen my $perlvar = shift @$found_things; 1028898184e3Ssthen open(PVAR, "<", $perlvar) # "Funk is its own reward" 1029898184e3Ssthen or $self->die("Can't open $perlvar: $!"); 1030898184e3Ssthen 1031898184e3Ssthen if ( $opt ne '$0' && $opt =~ /^\$\d+$/ ) { # handle $1, $2, ... 1032898184e3Ssthen $opt = '$<I<digits>>'; 1033898184e3Ssthen } 1034898184e3Ssthen my $search_re = quotemeta($opt); 1035898184e3Ssthen 1036898184e3Ssthen DEBUG > 2 and 1037898184e3Ssthen print "Going to perlvar-scan for $search_re in $perlvar\n"; 1038898184e3Ssthen 1039898184e3Ssthen # Skip introduction 1040898184e3Ssthen local $_; 1041898184e3Ssthen while (<PVAR>) { 1042898184e3Ssthen last if /^=over 8/; 1043898184e3Ssthen } 1044898184e3Ssthen 1045898184e3Ssthen # Look for our variable 1046898184e3Ssthen my $found = 0; 1047898184e3Ssthen my $inheader = 1; 1048898184e3Ssthen my $inlist = 0; 1049898184e3Ssthen while (<PVAR>) { # "The Mothership Connection is here!" 1050898184e3Ssthen last if /^=head2 Error Indicators/; 1051898184e3Ssthen # \b at the end of $` and friends borks things! 1052898184e3Ssthen if ( m/^=item\s+$search_re\s/ ) { 1053898184e3Ssthen $found = 1; 1054898184e3Ssthen } 1055898184e3Ssthen elsif (/^=item/) { 1056898184e3Ssthen last if $found && !$inheader && !$inlist; 1057898184e3Ssthen } 1058898184e3Ssthen elsif (!/^\s+$/) { # not a blank line 1059898184e3Ssthen if ( $found ) { 1060898184e3Ssthen $inheader = 0; # don't accept more =item (unless inlist) 1061898184e3Ssthen } 1062898184e3Ssthen else { 1063898184e3Ssthen @$pod = (); # reset 1064898184e3Ssthen $inheader = 1; # start over 1065898184e3Ssthen next; 1066898184e3Ssthen } 1067898184e3Ssthen } 1068898184e3Ssthen 1069898184e3Ssthen if (/^=over/) { 1070898184e3Ssthen ++$inlist; 1071898184e3Ssthen } 1072898184e3Ssthen elsif (/^=back/) { 1073898184e3Ssthen last if $found && !$inheader && !$inlist; 1074898184e3Ssthen --$inlist; 1075898184e3Ssthen } 1076898184e3Ssthen push @$pod, $_; 1077898184e3Ssthen# ++$found if /^\w/; # found descriptive text 1078898184e3Ssthen } 1079898184e3Ssthen @$pod = () unless $found; 1080898184e3Ssthen if (!@$pod) { 1081898184e3Ssthen CORE::die( "No documentation for perl variable '$opt' found\n" ); 1082898184e3Ssthen } 1083898184e3Ssthen close PVAR or $self->die( "Can't open $perlvar: $!" ); 1084898184e3Ssthen 1085898184e3Ssthen return; 1086898184e3Ssthen} 1087898184e3Ssthen 1088898184e3Ssthen#.......................................................................... 1089898184e3Ssthen 1090898184e3Ssthensub search_perlop { 1091898184e3Ssthen my ($self,$found_things,$pod) = @_; 1092898184e3Ssthen 1093898184e3Ssthen $self->not_dynamic( 1 ); 1094898184e3Ssthen 1095898184e3Ssthen my $perlop = shift @$found_things; 1096898184e3Ssthen open( PERLOP, '<', $perlop ) or $self->die( "Can't open $perlop: $!" ); 1097898184e3Ssthen 1098898184e3Ssthen my $paragraph = ""; 1099898184e3Ssthen my $has_text_seen = 0; 1100898184e3Ssthen my $thing = $self->opt_f; 1101898184e3Ssthen my $list = 0; 1102898184e3Ssthen 1103898184e3Ssthen while( my $line = <PERLOP> ){ 1104898184e3Ssthen if( $paragraph and $line =~ m!^=(?:head|item)! and $paragraph =~ m!X<+\s*\Q$thing\E\s*>+! ){ 1105898184e3Ssthen if( $list ){ 1106898184e3Ssthen $paragraph =~ s!=back.*?\z!!s; 1107898184e3Ssthen } 1108898184e3Ssthen 1109898184e3Ssthen if( $paragraph =~ m!^=item! ){ 1110898184e3Ssthen $paragraph = "=over 8\n\n" . $paragraph . "=back\n"; 1111898184e3Ssthen } 1112898184e3Ssthen 1113898184e3Ssthen push @$pod, $paragraph; 1114898184e3Ssthen $paragraph = ""; 1115898184e3Ssthen $has_text_seen = 0; 1116898184e3Ssthen $list = 0; 1117898184e3Ssthen } 1118898184e3Ssthen 1119898184e3Ssthen if( $line =~ m!^=over! ){ 1120898184e3Ssthen $list++; 1121898184e3Ssthen } 1122898184e3Ssthen elsif( $line =~ m!^=back! ){ 1123898184e3Ssthen $list--; 1124898184e3Ssthen } 1125898184e3Ssthen 1126898184e3Ssthen if( $line =~ m!^=(?:head|item)! and $has_text_seen ){ 1127898184e3Ssthen $paragraph = ""; 1128898184e3Ssthen } 1129898184e3Ssthen elsif( $line !~ m!^=(?:head|item)! and $line !~ m!^\s*$! and $line !~ m!^\s*X<! ){ 1130898184e3Ssthen $has_text_seen = 1; 1131898184e3Ssthen } 1132898184e3Ssthen 1133898184e3Ssthen $paragraph .= $line; 1134898184e3Ssthen } 1135898184e3Ssthen 1136898184e3Ssthen close PERLOP; 1137898184e3Ssthen 1138898184e3Ssthen return; 1139898184e3Ssthen} 1140898184e3Ssthen 1141898184e3Ssthen#.......................................................................... 1142898184e3Ssthen 1143898184e3Ssthensub search_perlfunc { 1144898184e3Ssthen my($self, $found_things, $pod) = @_; 1145898184e3Ssthen 1146898184e3Ssthen DEBUG > 2 and print "Search: @$found_things\n"; 1147898184e3Ssthen 1148898184e3Ssthen my $perlfunc = shift @$found_things; 1149898184e3Ssthen open(PFUNC, "<", $perlfunc) # "Funk is its own reward" 1150898184e3Ssthen or $self->die("Can't open $perlfunc: $!"); 1151898184e3Ssthen 1152898184e3Ssthen # Functions like -r, -e, etc. are listed under `-X'. 1153898184e3Ssthen my $search_re = ($self->opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/) 1154898184e3Ssthen ? '(?:I<)?-X' : quotemeta($self->opt_f) ; 1155898184e3Ssthen 1156898184e3Ssthen DEBUG > 2 and 1157898184e3Ssthen print "Going to perlfunc-scan for $search_re in $perlfunc\n"; 1158898184e3Ssthen 1159898184e3Ssthen my $re = 'Alphabetical Listing of Perl Functions'; 1160898184e3Ssthen 1161898184e3Ssthen # Check available translator or backup to default (english) 1162898184e3Ssthen if ( $self->opt_L && defined $self->{'translators'}->[0] ) { 1163898184e3Ssthen my $tr = $self->{'translators'}->[0]; 1164898184e3Ssthen $re = $tr->search_perlfunc_re if $tr->can('search_perlfunc_re'); 1165898184e3Ssthen } 1166898184e3Ssthen 1167898184e3Ssthen # Skip introduction 1168898184e3Ssthen local $_; 1169898184e3Ssthen while (<PFUNC>) { 1170898184e3Ssthen last if /^=head2 $re/; 1171898184e3Ssthen } 1172898184e3Ssthen 1173898184e3Ssthen # Look for our function 1174898184e3Ssthen my $found = 0; 1175898184e3Ssthen my $inlist = 0; 1176898184e3Ssthen 1177898184e3Ssthen my @perlops = qw(m q qq qr qx qw s tr y); 1178898184e3Ssthen 1179898184e3Ssthen my @related; 1180898184e3Ssthen my $related_re; 1181898184e3Ssthen while (<PFUNC>) { # "The Mothership Connection is here!" 1182898184e3Ssthen last if( grep{ $self->opt_f eq $_ }@perlops ); 1183898184e3Ssthen if ( m/^=item\s+$search_re\b/ ) { 1184898184e3Ssthen $found = 1; 1185898184e3Ssthen } 1186898184e3Ssthen elsif (@related > 1 and /^=item/) { 1187898184e3Ssthen $related_re ||= join "|", @related; 1188898184e3Ssthen if (m/^=item\s+(?:$related_re)\b/) { 1189898184e3Ssthen $found = 1; 1190898184e3Ssthen } 1191898184e3Ssthen else { 1192898184e3Ssthen last; 1193898184e3Ssthen } 1194898184e3Ssthen } 1195898184e3Ssthen elsif (/^=item/) { 1196898184e3Ssthen last if $found > 1 and not $inlist; 1197898184e3Ssthen } 1198898184e3Ssthen elsif ($found and /^X<[^>]+>/) { 1199898184e3Ssthen push @related, m/X<([^>]+)>/g; 1200898184e3Ssthen } 1201898184e3Ssthen next unless $found; 1202898184e3Ssthen if (/^=over/) { 1203898184e3Ssthen ++$inlist; 1204898184e3Ssthen } 1205898184e3Ssthen elsif (/^=back/) { 1206898184e3Ssthen last if $found > 1 and not $inlist; 1207898184e3Ssthen --$inlist; 1208898184e3Ssthen } 1209898184e3Ssthen push @$pod, $_; 1210898184e3Ssthen ++$found if /^\w/; # found descriptive text 1211898184e3Ssthen } 1212898184e3Ssthen 1213898184e3Ssthen if( !@$pod ){ 1214898184e3Ssthen $self->search_perlop( $found_things, $pod ); 1215898184e3Ssthen } 1216898184e3Ssthen 1217898184e3Ssthen if (!@$pod) { 1218898184e3Ssthen CORE::die( sprintf 1219898184e3Ssthen "No documentation for perl function '%s' found\n", 1220898184e3Ssthen $self->opt_f ) 1221898184e3Ssthen ; 1222898184e3Ssthen } 1223898184e3Ssthen close PFUNC or $self->die( "Can't open $perlfunc: $!" ); 1224898184e3Ssthen 1225898184e3Ssthen return; 1226898184e3Ssthen} 1227898184e3Ssthen 1228898184e3Ssthen#.......................................................................... 1229898184e3Ssthen 1230898184e3Ssthensub search_perlfaqs { 1231898184e3Ssthen my( $self, $found_things, $pod) = @_; 1232898184e3Ssthen 1233898184e3Ssthen my $found = 0; 1234898184e3Ssthen my %found_in; 1235898184e3Ssthen my $search_key = $self->opt_q; 1236898184e3Ssthen 1237898184e3Ssthen my $rx = eval { qr/$search_key/ } 1238898184e3Ssthen or $self->die( <<EOD ); 1239898184e3SsthenInvalid regular expression '$search_key' given as -q pattern: 1240898184e3Ssthen$@ 1241898184e3SsthenDid you mean \\Q$search_key ? 1242898184e3Ssthen 1243898184e3SsthenEOD 1244898184e3Ssthen 1245898184e3Ssthen local $_; 1246898184e3Ssthen foreach my $file (@$found_things) { 1247898184e3Ssthen $self->die( "invalid file spec: $!" ) if $file =~ /[<>|]/; 1248898184e3Ssthen open(INFAQ, "<", $file) # XXX 5.6ism 1249898184e3Ssthen or $self->die( "Can't read-open $file: $!\nAborting" ); 1250898184e3Ssthen while (<INFAQ>) { 1251898184e3Ssthen if ( m/^=head2\s+.*(?:$search_key)/i ) { 1252898184e3Ssthen $found = 1; 1253898184e3Ssthen push @$pod, "=head1 Found in $file\n\n" unless $found_in{$file}++; 1254898184e3Ssthen } 1255898184e3Ssthen elsif (/^=head[12]/) { 1256898184e3Ssthen $found = 0; 1257898184e3Ssthen } 1258898184e3Ssthen next unless $found; 1259898184e3Ssthen push @$pod, $_; 1260898184e3Ssthen } 1261898184e3Ssthen close(INFAQ); 1262898184e3Ssthen } 1263898184e3Ssthen CORE::die("No documentation for perl FAQ keyword '$search_key' found\n") 1264898184e3Ssthen unless @$pod; 1265898184e3Ssthen 1266898184e3Ssthen if ( $self->opt_l ) { 1267898184e3Ssthen CORE::die((join "\n", keys %found_in) . "\n"); 1268898184e3Ssthen } 1269898184e3Ssthen return; 1270898184e3Ssthen} 1271898184e3Ssthen 1272898184e3Ssthen 1273898184e3Ssthen#.......................................................................... 1274898184e3Ssthen 1275898184e3Ssthensub render_findings { 1276898184e3Ssthen # Return the filename to open 1277898184e3Ssthen 1278898184e3Ssthen my($self, $found_things) = @_; 1279898184e3Ssthen 1280898184e3Ssthen my $formatter_class = $self->{'formatter_class'} 1281898184e3Ssthen || $self->die( "No formatter class set!?" ); 1282898184e3Ssthen my $formatter = $formatter_class->can('new') 1283898184e3Ssthen ? $formatter_class->new 1284898184e3Ssthen : $formatter_class 1285898184e3Ssthen ; 1286898184e3Ssthen 1287898184e3Ssthen if(! @$found_things) { 1288898184e3Ssthen $self->die( "Nothing found?!" ); 1289898184e3Ssthen # should have been caught before here 1290898184e3Ssthen } elsif(@$found_things > 1) { 1291898184e3Ssthen $self->warn( 1292898184e3Ssthen "Perldoc is only really meant for reading one document at a time.\n", 1293898184e3Ssthen "So these parameters are being ignored: ", 1294898184e3Ssthen join(' ', @$found_things[1 .. $#$found_things] ), 1295898184e3Ssthen "\n" ); 1296898184e3Ssthen } 1297898184e3Ssthen 1298898184e3Ssthen my $file = $found_things->[0]; 1299898184e3Ssthen 1300898184e3Ssthen DEBUG > 3 and printf "Formatter switches now: [%s]\n", 1301898184e3Ssthen join ' ', map "[@$_]", @{ $self->{'formatter_switches'} }; 1302898184e3Ssthen 1303898184e3Ssthen # Set formatter options: 1304898184e3Ssthen if( ref $formatter ) { 1305898184e3Ssthen foreach my $f (@{ $self->{'formatter_switches'} || [] }) { 1306898184e3Ssthen my($switch, $value, $silent_fail) = @$f; 1307898184e3Ssthen if( $formatter->can($switch) ) { 1308898184e3Ssthen eval { $formatter->$switch( defined($value) ? $value : () ) }; 1309898184e3Ssthen $self->warn( "Got an error when setting $formatter_class\->$switch:\n$@\n" ) 1310898184e3Ssthen if $@; 1311898184e3Ssthen } else { 1312898184e3Ssthen if( $silent_fail or $switch =~ m/^__/s ) { 1313898184e3Ssthen DEBUG > 2 and print "Formatter $formatter_class doesn't support $switch\n"; 1314898184e3Ssthen } else { 1315898184e3Ssthen $self->warn( "$formatter_class doesn't recognize the $switch switch.\n" ); 1316898184e3Ssthen } 1317898184e3Ssthen } 1318898184e3Ssthen } 1319898184e3Ssthen } 1320898184e3Ssthen 1321898184e3Ssthen $self->{'output_is_binary'} = 1322898184e3Ssthen $formatter->can('write_with_binmode') && $formatter->write_with_binmode; 1323898184e3Ssthen 1324898184e3Ssthen if( $self->{podnames} and exists $self->{podnames}{$file} and 1325898184e3Ssthen $formatter->can('name') ) { 1326898184e3Ssthen $formatter->name($self->{podnames}{$file}); 1327898184e3Ssthen } 1328898184e3Ssthen 1329898184e3Ssthen my ($out_fh, $out) = $self->new_output_file( 1330898184e3Ssthen ( $formatter->can('output_extension') && $formatter->output_extension ) 1331898184e3Ssthen || undef, 1332898184e3Ssthen $self->useful_filename_bit, 1333898184e3Ssthen ); 1334898184e3Ssthen 1335898184e3Ssthen # Now, finally, do the formatting! 1336898184e3Ssthen { 1337898184e3Ssthen local $^W = $^W; 1338898184e3Ssthen if(DEBUG() or $self->opt_D) { 1339898184e3Ssthen # feh, let 'em see it 1340898184e3Ssthen } else { 1341898184e3Ssthen $^W = 0; 1342898184e3Ssthen # The average user just has no reason to be seeing 1343898184e3Ssthen # $^W-suppressible warnings from the formatting! 1344898184e3Ssthen } 1345898184e3Ssthen 1346898184e3Ssthen eval { $formatter->parse_from_file( $file, $out_fh ) }; 1347898184e3Ssthen } 1348898184e3Ssthen 1349898184e3Ssthen $self->warn( "Error while formatting with $formatter_class:\n $@\n" ) if $@; 1350898184e3Ssthen DEBUG > 2 and print "Back from formatting with $formatter_class\n"; 1351898184e3Ssthen 1352898184e3Ssthen close $out_fh 1353898184e3Ssthen or $self->warn( "Can't close $out: $!\n(Did $formatter already close it?)" ); 1354898184e3Ssthen sleep 0; sleep 0; sleep 0; 1355898184e3Ssthen # Give the system a few timeslices to meditate on the fact 1356898184e3Ssthen # that the output file does in fact exist and is closed. 1357898184e3Ssthen 1358898184e3Ssthen $self->unlink_if_temp_file($file); 1359898184e3Ssthen 1360898184e3Ssthen unless( -s $out ) { 1361898184e3Ssthen if( $formatter->can( 'if_zero_length' ) ) { 1362898184e3Ssthen # Basically this is just a hook for Pod::Simple::Checker; since 1363898184e3Ssthen # what other class could /happily/ format an input file with Pod 1364898184e3Ssthen # as a 0-length output file? 1365898184e3Ssthen $formatter->if_zero_length( $file, $out, $out_fh ); 1366898184e3Ssthen } else { 1367898184e3Ssthen $self->warn( "Got a 0-length file from $$found_things[0] via $formatter_class!?\n" ); 1368898184e3Ssthen } 1369898184e3Ssthen } 1370898184e3Ssthen 1371898184e3Ssthen DEBUG and print "Finished writing to $out.\n"; 1372898184e3Ssthen return($out, $formatter) if wantarray; 1373898184e3Ssthen return $out; 1374898184e3Ssthen} 1375898184e3Ssthen 1376898184e3Ssthen#.......................................................................... 1377898184e3Ssthen 1378898184e3Ssthensub unlink_if_temp_file { 1379898184e3Ssthen # Unlink the specified file IFF it's in the list of temp files. 1380898184e3Ssthen # Really only used in the case of -f / -q things when we can 1381898184e3Ssthen # throw away the dynamically generated source pod file once 1382898184e3Ssthen # we've formatted it. 1383898184e3Ssthen # 1384898184e3Ssthen my($self, $file) = @_; 1385898184e3Ssthen return unless defined $file and length $file; 1386898184e3Ssthen 1387898184e3Ssthen my $temp_file_list = $self->{'temp_file_list'} || return; 1388898184e3Ssthen if(grep $_ eq $file, @$temp_file_list) { 1389898184e3Ssthen $self->aside("Unlinking $file\n"); 1390898184e3Ssthen unlink($file) or $self->warn( "Odd, couldn't unlink $file: $!" ); 1391898184e3Ssthen } else { 1392898184e3Ssthen DEBUG > 1 and print "$file isn't a temp file, so not unlinking.\n"; 1393898184e3Ssthen } 1394898184e3Ssthen return; 1395898184e3Ssthen} 1396898184e3Ssthen 1397898184e3Ssthen#.......................................................................... 1398898184e3Ssthen 1399898184e3Ssthen 1400898184e3Ssthensub after_rendering { 1401898184e3Ssthen my $self = $_[0]; 1402898184e3Ssthen $self->after_rendering_VMS if $self->is_vms; 1403898184e3Ssthen $self->after_rendering_MSWin32 if $self->is_mswin32; 1404898184e3Ssthen $self->after_rendering_Dos if $self->is_dos; 1405898184e3Ssthen $self->after_rendering_OS2 if $self->is_os2; 1406898184e3Ssthen return; 1407898184e3Ssthen} 1408898184e3Ssthen 1409898184e3Ssthensub after_rendering_VMS { return } 1410898184e3Ssthensub after_rendering_Dos { return } 1411898184e3Ssthensub after_rendering_OS2 { return } 1412898184e3Ssthensub after_rendering_MSWin32 { return } 1413898184e3Ssthen 1414898184e3Ssthen#.......................................................................... 1415898184e3Ssthen# : : : : : : : : : 1416898184e3Ssthen#.......................................................................... 1417898184e3Ssthen 1418898184e3Ssthensub minus_f_nocase { # i.e., do like -f, but without regard to case 1419898184e3Ssthen 1420898184e3Ssthen my($self, $dir, $file) = @_; 1421898184e3Ssthen my $path = catfile($dir,$file); 1422898184e3Ssthen return $path if -f $path and -r _; 1423898184e3Ssthen 1424898184e3Ssthen if(!$self->opt_i 1425898184e3Ssthen or $self->is_vms or $self->is_mswin32 1426*91f110e0Safresh1 or $self->is_dos or $self->is_os2 1427898184e3Ssthen ) { 1428898184e3Ssthen # On a case-forgiving file system, or if case is important, 1429898184e3Ssthen # that is it, all we can do. 1430898184e3Ssthen $self->warn( "Ignored $path: unreadable\n" ) if -f _; 1431898184e3Ssthen return ''; 1432898184e3Ssthen } 1433898184e3Ssthen 1434898184e3Ssthen local *DIR; 1435898184e3Ssthen my @p = ($dir); 1436898184e3Ssthen my($p,$cip); 1437898184e3Ssthen foreach $p (splitdir $file){ 1438898184e3Ssthen my $try = catfile @p, $p; 1439898184e3Ssthen $self->aside("Scrutinizing $try...\n"); 1440898184e3Ssthen stat $try; 1441898184e3Ssthen if (-d _) { 1442898184e3Ssthen push @p, $p; 1443898184e3Ssthen if ( $p eq $self->{'target'} ) { 1444898184e3Ssthen my $tmp_path = catfile @p; 1445898184e3Ssthen my $path_f = 0; 1446898184e3Ssthen for (@{ $self->{'found'} }) { 1447898184e3Ssthen $path_f = 1 if $_ eq $tmp_path; 1448898184e3Ssthen } 1449898184e3Ssthen push (@{ $self->{'found'} }, $tmp_path) unless $path_f; 1450898184e3Ssthen $self->aside( "Found as $tmp_path but directory\n" ); 1451898184e3Ssthen } 1452898184e3Ssthen } 1453898184e3Ssthen elsif (-f _ && -r _ && lc($try) eq lc($path)) { 1454898184e3Ssthen return $try; 1455898184e3Ssthen } 1456898184e3Ssthen elsif (-f _) { 1457898184e3Ssthen $self->warn( "Ignored $try: unreadable or file/dir mismatch\n" ); 1458898184e3Ssthen } 1459898184e3Ssthen elsif (-d catdir(@p)) { # at least we see the containing directory! 1460898184e3Ssthen my $found = 0; 1461898184e3Ssthen my $lcp = lc $p; 1462898184e3Ssthen my $p_dirspec = catdir(@p); 1463898184e3Ssthen opendir DIR, $p_dirspec or $self->die( "opendir $p_dirspec: $!" ); 1464898184e3Ssthen while(defined( $cip = readdir(DIR) )) { 1465898184e3Ssthen if (lc $cip eq $lcp){ 1466898184e3Ssthen $found++; 1467898184e3Ssthen last; # XXX stop at the first? what if there's others? 1468898184e3Ssthen } 1469898184e3Ssthen } 1470898184e3Ssthen closedir DIR or $self->die( "closedir $p_dirspec: $!" ); 1471898184e3Ssthen return "" unless $found; 1472898184e3Ssthen 1473898184e3Ssthen push @p, $cip; 1474898184e3Ssthen my $p_filespec = catfile(@p); 1475898184e3Ssthen return $p_filespec if -f $p_filespec and -r _; 1476898184e3Ssthen $self->warn( "Ignored $p_filespec: unreadable\n" ) if -f _; 1477898184e3Ssthen } 1478898184e3Ssthen } 1479898184e3Ssthen return ""; 1480898184e3Ssthen} 1481898184e3Ssthen 1482898184e3Ssthen#.......................................................................... 1483898184e3Ssthen 1484898184e3Ssthensub pagers_guessing { 1485898184e3Ssthen my $self = shift; 1486898184e3Ssthen 1487898184e3Ssthen my @pagers; 1488898184e3Ssthen push @pagers, $self->pagers; 1489898184e3Ssthen $self->{'pagers'} = \@pagers; 1490898184e3Ssthen 1491898184e3Ssthen if ($self->is_mswin32) { 1492898184e3Ssthen push @pagers, qw( more< less notepad ); 1493898184e3Ssthen unshift @pagers, $ENV{PAGER} if $ENV{PAGER}; 1494898184e3Ssthen } 1495898184e3Ssthen elsif ($self->is_vms) { 1496898184e3Ssthen push @pagers, qw( most more less type/page ); 1497898184e3Ssthen } 1498898184e3Ssthen elsif ($self->is_dos) { 1499898184e3Ssthen push @pagers, qw( less.exe more.com< ); 1500898184e3Ssthen unshift @pagers, $ENV{PAGER} if $ENV{PAGER}; 1501898184e3Ssthen } 1502898184e3Ssthen else { 1503898184e3Ssthen if ($self->is_os2) { 1504898184e3Ssthen unshift @pagers, 'less', 'cmd /c more <'; 1505898184e3Ssthen } 1506898184e3Ssthen push @pagers, qw( more less pg view cat ); 1507898184e3Ssthen unshift @pagers, "$ENV{PAGER} <" if $ENV{PAGER}; 1508898184e3Ssthen } 1509898184e3Ssthen 1510898184e3Ssthen if ($self->is_cygwin) { 1511898184e3Ssthen if (($pagers[0] eq 'less') || ($pagers[0] eq '/usr/bin/less')) { 1512898184e3Ssthen unshift @pagers, '/usr/bin/less -isrR'; 1513898184e3Ssthen unshift @pagers, $ENV{PAGER} if $ENV{PAGER}; 1514898184e3Ssthen } 1515898184e3Ssthen } 1516898184e3Ssthen 1517*91f110e0Safresh1 unshift @pagers, "$ENV{PERLDOC_PAGER} <" if $ENV{PERLDOC_PAGER}; 1518898184e3Ssthen 1519898184e3Ssthen return; 1520898184e3Ssthen} 1521898184e3Ssthen 1522898184e3Ssthen#.......................................................................... 1523898184e3Ssthen 1524898184e3Ssthensub page_module_file { 1525898184e3Ssthen my($self, @found) = @_; 1526898184e3Ssthen 1527898184e3Ssthen # Security note: 1528898184e3Ssthen # Don't ever just pass this off to anything like MSWin's "start.exe", 1529898184e3Ssthen # since we might be calling on a .pl file, and we wouldn't want that 1530898184e3Ssthen # to actually /execute/ the file that we just want to page thru! 1531898184e3Ssthen # Also a consideration if one were to use a web browser as a pager; 1532898184e3Ssthen # doing so could trigger the browser's MIME mapping for whatever 1533898184e3Ssthen # it thinks .pm/.pl/whatever is. Probably just a (useless and 1534898184e3Ssthen # annoying) "Save as..." dialog, but potentially executing the file 1535898184e3Ssthen # in question -- particularly in the case of MSIE and it's, ahem, 1536898184e3Ssthen # occasionally hazy distinction between OS-local extension 1537898184e3Ssthen # associations, and browser-specific MIME mappings. 1538898184e3Ssthen 1539898184e3Ssthen if(@found > 1) { 1540898184e3Ssthen $self->warn( 1541898184e3Ssthen "Perldoc is only really meant for reading one document at a time.\n" . 1542898184e3Ssthen "So these files are being ignored: " . 1543898184e3Ssthen join(' ', @found[1 .. $#found] ) . 1544898184e3Ssthen "\n" ) 1545898184e3Ssthen } 1546898184e3Ssthen 1547898184e3Ssthen return $self->page($found[0], $self->{'output_to_stdout'}, $self->pagers); 1548898184e3Ssthen 1549898184e3Ssthen} 1550898184e3Ssthen 1551898184e3Ssthen#.......................................................................... 1552898184e3Ssthen 1553898184e3Ssthensub check_file { 1554898184e3Ssthen my($self, $dir, $file) = @_; 1555898184e3Ssthen 1556898184e3Ssthen unless( ref $self ) { 1557898184e3Ssthen # Should never get called: 1558898184e3Ssthen $Carp::Verbose = 1; 1559898184e3Ssthen require Carp; 1560898184e3Ssthen Carp::croak( join '', 1561898184e3Ssthen "Crazy ", __PACKAGE__, " error:\n", 1562898184e3Ssthen "check_file must be an object_method!\n", 1563898184e3Ssthen "Aborting" 1564898184e3Ssthen ); 1565898184e3Ssthen } 1566898184e3Ssthen 1567898184e3Ssthen if(length $dir and not -d $dir) { 1568898184e3Ssthen DEBUG > 3 and print " No dir $dir -- skipping.\n"; 1569898184e3Ssthen return ""; 1570898184e3Ssthen } 1571898184e3Ssthen 1572898184e3Ssthen my $path = $self->minus_f_nocase($dir,$file); 1573898184e3Ssthen if( length $path and ($self->opt_m ? $self->isprintable($path) 1574898184e3Ssthen : $self->containspod($path)) ) { 1575898184e3Ssthen DEBUG > 3 and print 1576898184e3Ssthen " The file $path indeed looks promising!\n"; 1577898184e3Ssthen return $path; 1578898184e3Ssthen } 1579898184e3Ssthen DEBUG > 3 and print " No good: $file in $dir\n"; 1580898184e3Ssthen 1581898184e3Ssthen return ""; 1582898184e3Ssthen} 1583898184e3Ssthen 1584898184e3Ssthensub isprintable { 1585898184e3Ssthen my($self, $file, $readit) = @_; 1586898184e3Ssthen my $size= 1024; 1587898184e3Ssthen my $maxunprintfrac= 0.2; # tolerate some unprintables for UTF-8 comments etc. 1588898184e3Ssthen 1589898184e3Ssthen return 1 if !$readit && $file =~ /\.(?:pl|pm|pod|cmd|com|bat)\z/i; 1590898184e3Ssthen 1591898184e3Ssthen my $data; 1592898184e3Ssthen local($_); 1593898184e3Ssthen open(TEST,"<", $file) or $self->die( "Can't open $file: $!" ); 1594898184e3Ssthen read TEST, $data, $size; 1595898184e3Ssthen close TEST; 1596898184e3Ssthen $size= length($data); 1597898184e3Ssthen $data =~ tr/\x09-\x0D\x20-\x7E//d; 1598898184e3Ssthen return length($data) <= $size*$maxunprintfrac; 1599898184e3Ssthen} 1600898184e3Ssthen 1601898184e3Ssthen#.......................................................................... 1602898184e3Ssthen 1603898184e3Ssthensub containspod { 1604898184e3Ssthen my($self, $file, $readit) = @_; 1605898184e3Ssthen return 1 if !$readit && $file =~ /\.pod\z/i; 1606898184e3Ssthen 1607898184e3Ssthen 1608898184e3Ssthen # Under cygwin the /usr/bin/perl is legal executable, but 1609898184e3Ssthen # you cannot open a file with that name. It must be spelled 1610898184e3Ssthen # out as "/usr/bin/perl.exe". 1611898184e3Ssthen # 1612898184e3Ssthen # The following if-case under cygwin prevents error 1613898184e3Ssthen # 1614898184e3Ssthen # $ perldoc perl 1615898184e3Ssthen # Cannot open /usr/bin/perl: no such file or directory 1616898184e3Ssthen # 1617898184e3Ssthen # This would work though 1618898184e3Ssthen # 1619898184e3Ssthen # $ perldoc perl.pod 1620898184e3Ssthen 1621898184e3Ssthen if ( $self->is_cygwin and -x $file and -f "$file.exe" ) 1622898184e3Ssthen { 1623898184e3Ssthen $self->warn( "Cygwin $file.exe search skipped\n" ) if DEBUG or $self->opt_D; 1624898184e3Ssthen return 0; 1625898184e3Ssthen } 1626898184e3Ssthen 1627898184e3Ssthen local($_); 1628898184e3Ssthen open(TEST,"<", $file) or $self->die( "Can't open $file: $!" ); # XXX 5.6ism 1629898184e3Ssthen while (<TEST>) { 1630898184e3Ssthen if (/^=head/) { 1631898184e3Ssthen close(TEST) or $self->die( "Can't close $file: $!" ); 1632898184e3Ssthen return 1; 1633898184e3Ssthen } 1634898184e3Ssthen } 1635898184e3Ssthen close(TEST) or $self->die( "Can't close $file: $!" ); 1636898184e3Ssthen return 0; 1637898184e3Ssthen} 1638898184e3Ssthen 1639898184e3Ssthen#.......................................................................... 1640898184e3Ssthen 1641898184e3Ssthensub maybe_diddle_INC { 1642898184e3Ssthen my $self = shift; 1643898184e3Ssthen 1644898184e3Ssthen # Does this look like a module or extension directory? 1645898184e3Ssthen 1646898184e3Ssthen if (-f "Makefile.PL" || -f "Build.PL") { 1647898184e3Ssthen 1648898184e3Ssthen # Add "." and "lib" to @INC (if they exist) 1649898184e3Ssthen eval q{ use lib qw(. lib); 1; } or $self->die; 1650898184e3Ssthen 1651898184e3Ssthen # don't add if superuser 1652898184e3Ssthen if ($< && $> && -d "blib") { # don't be looking too hard now! 1653898184e3Ssthen eval q{ use blib; 1 }; 1654898184e3Ssthen $self->warn( $@ ) if $@ && $self->opt_D; 1655898184e3Ssthen } 1656898184e3Ssthen } 1657898184e3Ssthen 1658898184e3Ssthen return; 1659898184e3Ssthen} 1660898184e3Ssthen 1661898184e3Ssthen#.......................................................................... 1662898184e3Ssthen 1663898184e3Ssthensub new_output_file { 1664898184e3Ssthen my $self = shift; 1665898184e3Ssthen my $outspec = $self->opt_d; # Yes, -d overrides all else! 1666898184e3Ssthen # So don't call this twice per format-job! 1667898184e3Ssthen 1668898184e3Ssthen return $self->new_tempfile(@_) unless defined $outspec and length $outspec; 1669898184e3Ssthen 1670898184e3Ssthen # Otherwise open a write-handle on opt_d!f 1671898184e3Ssthen 1672898184e3Ssthen my $fh; 1673898184e3Ssthen # If we are running before perl5.6.0, we can't autovivify 1674898184e3Ssthen if ($^V < 5.006) { 1675898184e3Ssthen require Symbol; 1676898184e3Ssthen $fh = Symbol::gensym(); 1677898184e3Ssthen } 1678898184e3Ssthen DEBUG > 3 and print "About to try writing to specified output file $outspec\n"; 1679898184e3Ssthen $self->die( "Can't write-open $outspec: $!" ) 1680898184e3Ssthen unless open($fh, ">", $outspec); # XXX 5.6ism 1681898184e3Ssthen 1682898184e3Ssthen DEBUG > 3 and print "Successfully opened $outspec\n"; 1683898184e3Ssthen binmode($fh) if $self->{'output_is_binary'}; 1684898184e3Ssthen return($fh, $outspec); 1685898184e3Ssthen} 1686898184e3Ssthen 1687898184e3Ssthen#.......................................................................... 1688898184e3Ssthen 1689898184e3Ssthensub useful_filename_bit { 1690898184e3Ssthen # This tries to provide a meaningful bit of text to do with the query, 1691898184e3Ssthen # such as can be used in naming the file -- since if we're going to be 1692898184e3Ssthen # opening windows on temp files (as a "pager" may well do!) then it's 1693898184e3Ssthen # better if the temp file's name (which may well be used as the window 1694898184e3Ssthen # title) isn't ALL just random garbage! 1695898184e3Ssthen # In other words "perldoc_LWPSimple_2371981429" is a better temp file 1696898184e3Ssthen # name than "perldoc_2371981429". So this routine is what tries to 1697898184e3Ssthen # provide the "LWPSimple" bit. 1698898184e3Ssthen # 1699898184e3Ssthen my $self = shift; 1700898184e3Ssthen my $pages = $self->{'pages'} || return undef; 1701898184e3Ssthen return undef unless @$pages; 1702898184e3Ssthen 1703898184e3Ssthen my $chunk = $pages->[0]; 1704898184e3Ssthen return undef unless defined $chunk; 1705898184e3Ssthen $chunk =~ s/:://g; 1706898184e3Ssthen $chunk =~ s/\.\w+$//g; # strip any extension 1707898184e3Ssthen if( $chunk =~ m/([^\#\\:\/\$]+)$/s ) { # get basename, if it's a file 1708898184e3Ssthen $chunk = $1; 1709898184e3Ssthen } else { 1710898184e3Ssthen return undef; 1711898184e3Ssthen } 1712898184e3Ssthen $chunk =~ s/[^a-zA-Z0-9]+//g; # leave ONLY a-zA-Z0-9 things! 1713898184e3Ssthen $chunk = substr($chunk, -10) if length($chunk) > 10; 1714898184e3Ssthen return $chunk; 1715898184e3Ssthen} 1716898184e3Ssthen 1717898184e3Ssthen#.......................................................................... 1718898184e3Ssthen 1719898184e3Ssthensub new_tempfile { # $self->new_tempfile( [$suffix, [$infix] ] ) 1720898184e3Ssthen my $self = shift; 1721898184e3Ssthen 1722898184e3Ssthen ++$Temp_Files_Created; 1723898184e3Ssthen 1724898184e3Ssthen require File::Temp; 1725898184e3Ssthen return File::Temp::tempfile(UNLINK => 1); 1726898184e3Ssthen} 1727898184e3Ssthen 1728898184e3Ssthen#.......................................................................... 1729898184e3Ssthen 1730898184e3Ssthensub page { # apply a pager to the output file 1731898184e3Ssthen my ($self, $output, $output_to_stdout, @pagers) = @_; 1732898184e3Ssthen if ($output_to_stdout) { 1733898184e3Ssthen $self->aside("Sending unpaged output to STDOUT.\n"); 1734898184e3Ssthen open(TMP, "<", $output) or $self->die( "Can't open $output: $!" ); # XXX 5.6ism 1735898184e3Ssthen local $_; 1736898184e3Ssthen while (<TMP>) { 1737898184e3Ssthen print or $self->die( "Can't print to stdout: $!" ); 1738898184e3Ssthen } 1739898184e3Ssthen close TMP or $self->die( "Can't close while $output: $!" ); 1740898184e3Ssthen $self->unlink_if_temp_file($output); 1741898184e3Ssthen } else { 1742898184e3Ssthen # On VMS, quoting prevents logical expansion, and temp files with no 1743898184e3Ssthen # extension get the wrong default extension (such as .LIS for TYPE) 1744898184e3Ssthen 1745898184e3Ssthen $output = VMS::Filespec::rmsexpand($output, '.') if $self->is_vms; 1746898184e3Ssthen 1747898184e3Ssthen $output =~ s{/}{\\}g if $self->is_mswin32 || $self->is_dos; 1748898184e3Ssthen # Altho "/" under MSWin is in theory good as a pathsep, 1749898184e3Ssthen # many many corners of the OS don't like it. So we 1750898184e3Ssthen # have to force it to be "\" to make everyone happy. 1751898184e3Ssthen 1752898184e3Ssthen foreach my $pager (@pagers) { 1753898184e3Ssthen $self->aside("About to try calling $pager $output\n"); 1754898184e3Ssthen if ($self->is_vms) { 1755898184e3Ssthen last if system("$pager $output") == 0; 1756898184e3Ssthen } else { 1757898184e3Ssthen last if system("$pager \"$output\"") == 0; 1758898184e3Ssthen } 1759898184e3Ssthen } 1760898184e3Ssthen } 1761898184e3Ssthen return; 1762898184e3Ssthen} 1763898184e3Ssthen 1764898184e3Ssthen#.......................................................................... 1765898184e3Ssthen 1766898184e3Ssthensub searchfor { 1767898184e3Ssthen my($self, $recurse,$s,@dirs) = @_; 1768898184e3Ssthen $s =~ s!::!/!g; 1769898184e3Ssthen $s = VMS::Filespec::unixify($s) if $self->is_vms; 1770898184e3Ssthen return $s if -f $s && $self->containspod($s); 1771898184e3Ssthen $self->aside( "Looking for $s in @dirs\n" ); 1772898184e3Ssthen my $ret; 1773898184e3Ssthen my $i; 1774898184e3Ssthen my $dir; 1775898184e3Ssthen $self->{'target'} = (splitdir $s)[-1]; # XXX: why not use File::Basename? 1776898184e3Ssthen for ($i=0; $i<@dirs; $i++) { 1777898184e3Ssthen $dir = $dirs[$i]; 1778898184e3Ssthen next unless -d $dir; 1779898184e3Ssthen ($dir = VMS::Filespec::unixpath($dir)) =~ s!/\z!! if $self->is_vms; 1780898184e3Ssthen if ( (! $self->opt_m && ( $ret = $self->check_file($dir,"$s.pod"))) 1781898184e3Ssthen or ( $ret = $self->check_file($dir,"$s.pm")) 1782898184e3Ssthen or ( $ret = $self->check_file($dir,$s)) 1783898184e3Ssthen or ( $self->is_vms and 1784898184e3Ssthen $ret = $self->check_file($dir,"$s.com")) 1785898184e3Ssthen or ( $self->is_os2 and 1786898184e3Ssthen $ret = $self->check_file($dir,"$s.cmd")) 1787898184e3Ssthen or ( ($self->is_mswin32 or $self->is_dos or $self->is_os2) and 1788898184e3Ssthen $ret = $self->check_file($dir,"$s.bat")) 1789898184e3Ssthen or ( $ret = $self->check_file("$dir/pod","$s.pod")) 1790898184e3Ssthen or ( $ret = $self->check_file("$dir/pod",$s)) 1791898184e3Ssthen or ( $ret = $self->check_file("$dir/pods","$s.pod")) 1792898184e3Ssthen or ( $ret = $self->check_file("$dir/pods",$s)) 1793898184e3Ssthen ) { 1794898184e3Ssthen DEBUG > 1 and print " Found $ret\n"; 1795898184e3Ssthen return $ret; 1796898184e3Ssthen } 1797898184e3Ssthen 1798898184e3Ssthen if ($recurse) { 1799898184e3Ssthen opendir(D,$dir) or $self->die( "Can't opendir $dir: $!" ); 1800898184e3Ssthen my @newdirs = map catfile($dir, $_), grep { 1801898184e3Ssthen not /^\.\.?\z/s and 1802898184e3Ssthen not /^auto\z/s and # save time! don't search auto dirs 1803898184e3Ssthen -d catfile($dir, $_) 1804898184e3Ssthen } readdir D; 1805898184e3Ssthen closedir(D) or $self->die( "Can't closedir $dir: $!" ); 1806898184e3Ssthen next unless @newdirs; 1807898184e3Ssthen # what a wicked map! 1808898184e3Ssthen @newdirs = map((s/\.dir\z//,$_)[1],@newdirs) if $self->is_vms; 1809898184e3Ssthen $self->aside( "Also looking in @newdirs\n" ); 1810898184e3Ssthen push(@dirs,@newdirs); 1811898184e3Ssthen } 1812898184e3Ssthen } 1813898184e3Ssthen return (); 1814898184e3Ssthen} 1815898184e3Ssthen 1816898184e3Ssthen#.......................................................................... 1817898184e3Ssthen{ 1818898184e3Ssthen my $already_asserted; 1819898184e3Ssthen sub assert_closing_stdout { 1820898184e3Ssthen my $self = shift; 1821898184e3Ssthen 1822898184e3Ssthen return if $already_asserted; 1823898184e3Ssthen 1824898184e3Ssthen eval q~ END { close(STDOUT) || CORE::die "Can't close STDOUT: $!" } ~; 1825898184e3Ssthen # What for? to let the pager know that nothing more will come? 1826898184e3Ssthen 1827898184e3Ssthen $self->die( $@ ) if $@; 1828898184e3Ssthen $already_asserted = 1; 1829898184e3Ssthen return; 1830898184e3Ssthen } 1831898184e3Ssthen} 1832898184e3Ssthen 1833898184e3Ssthen#.......................................................................... 1834898184e3Ssthen 1835898184e3Ssthensub tweak_found_pathnames { 1836898184e3Ssthen my($self, $found) = @_; 1837898184e3Ssthen if ($self->is_mswin32) { 1838898184e3Ssthen foreach (@$found) { s,/,\\,g } 1839898184e3Ssthen } 1840898184e3Ssthen foreach (@$found) { s,',\\',g } # RT 37347 1841898184e3Ssthen return; 1842898184e3Ssthen} 1843898184e3Ssthen 1844898184e3Ssthen#.......................................................................... 1845898184e3Ssthen# : : : : : : : : : 1846898184e3Ssthen#.......................................................................... 1847898184e3Ssthen 1848898184e3Ssthensub am_taint_checking { 1849898184e3Ssthen my $self = shift; 1850898184e3Ssthen $self->die( "NO ENVIRONMENT?!?!" ) unless keys %ENV; # reset iterator along the way 1851898184e3Ssthen my($k,$v) = each %ENV; 1852898184e3Ssthen return is_tainted($v); 1853898184e3Ssthen} 1854898184e3Ssthen 1855898184e3Ssthen#.......................................................................... 1856898184e3Ssthen 1857898184e3Ssthensub is_tainted { # just a function 1858898184e3Ssthen my $arg = shift; 1859898184e3Ssthen my $nada = substr($arg, 0, 0); # zero-length! 1860898184e3Ssthen local $@; # preserve the caller's version of $@ 1861898184e3Ssthen eval { eval "# $nada" }; 1862898184e3Ssthen return length($@) != 0; 1863898184e3Ssthen} 1864898184e3Ssthen 1865898184e3Ssthen#.......................................................................... 1866898184e3Ssthen 1867898184e3Ssthensub drop_privs_maybe { 1868898184e3Ssthen my $self = shift; 1869898184e3Ssthen 1870898184e3Ssthen # Attempt to drop privs if we should be tainting and aren't 1871898184e3Ssthen if (!( $self->is_vms || $self->is_mswin32 || $self->is_dos 1872898184e3Ssthen || $self->is_os2 1873898184e3Ssthen ) 1874898184e3Ssthen && ($> == 0 || $< == 0) 1875898184e3Ssthen && !$self->am_taint_checking() 1876898184e3Ssthen ) { 1877898184e3Ssthen my $id = eval { getpwnam("nobody") }; 1878898184e3Ssthen $id = eval { getpwnam("nouser") } unless defined $id; 1879898184e3Ssthen $id = -2 unless defined $id; 1880898184e3Ssthen # 1881898184e3Ssthen # According to Stevens' APUE and various 1882898184e3Ssthen # (BSD, Solaris, HP-UX) man pages, setting 1883898184e3Ssthen # the real uid first and effective uid second 1884898184e3Ssthen # is the way to go if one wants to drop privileges, 1885898184e3Ssthen # because if one changes into an effective uid of 1886898184e3Ssthen # non-zero, one cannot change the real uid any more. 1887898184e3Ssthen # 1888898184e3Ssthen # Actually, it gets even messier. There is 1889898184e3Ssthen # a third uid, called the saved uid, and as 1890898184e3Ssthen # long as that is zero, one can get back to 1891898184e3Ssthen # uid of zero. Setting the real-effective *twice* 1892898184e3Ssthen # helps in *most* systems (FreeBSD and Solaris) 1893898184e3Ssthen # but apparently in HP-UX even this doesn't help: 1894898184e3Ssthen # the saved uid stays zero (apparently the only way 1895898184e3Ssthen # in HP-UX to change saved uid is to call setuid() 1896898184e3Ssthen # when the effective uid is zero). 1897898184e3Ssthen # 1898898184e3Ssthen eval { 1899898184e3Ssthen $< = $id; # real uid 1900898184e3Ssthen $> = $id; # effective uid 1901898184e3Ssthen $< = $id; # real uid 1902898184e3Ssthen $> = $id; # effective uid 1903898184e3Ssthen }; 1904898184e3Ssthen if( !$@ && $< && $> ) { 1905898184e3Ssthen DEBUG and print "OK, I dropped privileges.\n"; 1906898184e3Ssthen } elsif( $self->opt_U ) { 1907898184e3Ssthen DEBUG and print "Couldn't drop privileges, but in -U mode, so feh." 1908898184e3Ssthen } else { 1909898184e3Ssthen DEBUG and print "Hm, couldn't drop privileges. Ah well.\n"; 1910898184e3Ssthen # We used to die here; but that seemed pointless. 1911898184e3Ssthen } 1912898184e3Ssthen } 1913898184e3Ssthen return; 1914898184e3Ssthen} 1915898184e3Ssthen 1916898184e3Ssthen#.......................................................................... 1917898184e3Ssthen 1918898184e3Ssthen1; 1919898184e3Ssthen 1920898184e3Ssthen__END__ 1921898184e3Ssthen 1922898184e3Ssthen=head1 NAME 1923898184e3Ssthen 1924898184e3SsthenPod::Perldoc - Look up Perl documentation in Pod format. 1925898184e3Ssthen 1926898184e3Ssthen=head1 SYNOPSIS 1927898184e3Ssthen 1928898184e3Ssthen use Pod::Perldoc (); 1929898184e3Ssthen 1930898184e3Ssthen Pod::Perldoc->run(); 1931898184e3Ssthen 1932898184e3Ssthen=head1 DESCRIPTION 1933898184e3Ssthen 1934898184e3SsthenThe guts of L<perldoc> utility. 1935898184e3Ssthen 1936898184e3Ssthen=head1 SEE ALSO 1937898184e3Ssthen 1938898184e3SsthenL<perldoc> 1939898184e3Ssthen 1940898184e3Ssthen=head1 COPYRIGHT AND DISCLAIMERS 1941898184e3Ssthen 1942898184e3SsthenCopyright (c) 2002-2007 Sean M. Burke. 1943898184e3Ssthen 1944898184e3SsthenThis library is free software; you can redistribute it and/or modify it 1945898184e3Ssthenunder the same terms as Perl itself. 1946898184e3Ssthen 1947898184e3SsthenThis program is distributed in the hope that it will be useful, but 1948898184e3Ssthenwithout any warranty; without even the implied warranty of 1949898184e3Ssthenmerchantability or fitness for a particular purpose. 1950898184e3Ssthen 1951898184e3Ssthen=head1 AUTHOR 1952898184e3Ssthen 1953898184e3SsthenCurrent maintainer: Mark Allen C<< <mallen@cpan.org> >> 1954898184e3Ssthen 1955898184e3SsthenPast contributions from: 1956898184e3Ssthenbrian d foy C<< <bdfoy@cpan.org> >> 1957898184e3SsthenAdriano R. Ferreira C<< <ferreira@cpan.org> >>, 1958898184e3SsthenSean M. Burke C<< <sburke@cpan.org> >> 1959898184e3Ssthen 1960898184e3Ssthen=cut 1961