1*0Sstevel@tonic-gate 2*0Sstevel@tonic-gaterequire 5; 3*0Sstevel@tonic-gateuse 5.006; # we use some open(X, "<", $y) syntax 4*0Sstevel@tonic-gatepackage Pod::Perldoc; 5*0Sstevel@tonic-gateuse strict; 6*0Sstevel@tonic-gateuse warnings; 7*0Sstevel@tonic-gateuse Config '%Config'; 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gateuse Fcntl; # for sysopen 10*0Sstevel@tonic-gateuse File::Spec::Functions qw(catfile catdir splitdir); 11*0Sstevel@tonic-gate 12*0Sstevel@tonic-gateuse vars qw($VERSION @Pagers $Bindir $Pod2man 13*0Sstevel@tonic-gate $Temp_Files_Created $Temp_File_Lifetime 14*0Sstevel@tonic-gate); 15*0Sstevel@tonic-gate$VERSION = '3.12'; 16*0Sstevel@tonic-gate#.......................................................................... 17*0Sstevel@tonic-gate 18*0Sstevel@tonic-gateBEGIN { # Make a DEBUG constant very first thing... 19*0Sstevel@tonic-gate unless(defined &DEBUG) { 20*0Sstevel@tonic-gate if(($ENV{'PERLDOCDEBUG'} || '') =~ m/^(\d+)/) { # untaint 21*0Sstevel@tonic-gate eval("sub DEBUG () {$1}"); 22*0Sstevel@tonic-gate die "WHAT? Couldn't eval-up a DEBUG constant!? $@" if $@; 23*0Sstevel@tonic-gate } else { 24*0Sstevel@tonic-gate *DEBUG = sub () {0}; 25*0Sstevel@tonic-gate } 26*0Sstevel@tonic-gate } 27*0Sstevel@tonic-gate} 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gateuse Pod::Perldoc::GetOptsOO; # uses the DEBUG. 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate#.......................................................................... 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gatesub TRUE () {1} 34*0Sstevel@tonic-gatesub FALSE () {return} 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gateBEGIN { 37*0Sstevel@tonic-gate *IS_VMS = $^O eq 'VMS' ? \&TRUE : \&FALSE unless defined &IS_VMS; 38*0Sstevel@tonic-gate *IS_MSWin32 = $^O eq 'MSWin32' ? \&TRUE : \&FALSE unless defined &IS_MSWin32; 39*0Sstevel@tonic-gate *IS_Dos = $^O eq 'dos' ? \&TRUE : \&FALSE unless defined &IS_Dos; 40*0Sstevel@tonic-gate *IS_OS2 = $^O eq 'os2' ? \&TRUE : \&FALSE unless defined &IS_OS2; 41*0Sstevel@tonic-gate *IS_Cygwin = $^O eq 'cygwin' ? \&TRUE : \&FALSE unless defined &IS_Cygwin; 42*0Sstevel@tonic-gate *IS_Linux = $^O eq 'linux' ? \&TRUE : \&FALSE unless defined &IS_Linux; 43*0Sstevel@tonic-gate *IS_HPUX = $^O =~ m/hpux/ ? \&TRUE : \&FALSE unless defined &IS_HPUX; 44*0Sstevel@tonic-gate} 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate$Temp_File_Lifetime ||= 60 * 60 * 24 * 5; 47*0Sstevel@tonic-gate # If it's older than five days, it's quite unlikely 48*0Sstevel@tonic-gate # that anyone's still looking at it!! 49*0Sstevel@tonic-gate # (Currently used only by the MSWin cleanup routine) 50*0Sstevel@tonic-gate 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate#.......................................................................... 53*0Sstevel@tonic-gate{ my $pager = $Config{'pager'}; 54*0Sstevel@tonic-gate push @Pagers, $pager if -x (split /\s+/, $pager)[0] or IS_VMS; 55*0Sstevel@tonic-gate} 56*0Sstevel@tonic-gate$Bindir = $Config{'scriptdirexp'}; 57*0Sstevel@tonic-gate$Pod2man = "pod2man" . ( $Config{'versiononly'} ? $Config{'version'} : '' ); 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate# End of class-init stuff 60*0Sstevel@tonic-gate# 61*0Sstevel@tonic-gate########################################################################### 62*0Sstevel@tonic-gate# 63*0Sstevel@tonic-gate# Option accessors... 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gateforeach my $subname (map "opt_$_", split '', q{mhlvriFfXqnTdU}) { 66*0Sstevel@tonic-gate no strict 'refs'; 67*0Sstevel@tonic-gate *$subname = do{ use strict 'refs'; sub () { shift->_elem($subname, @_) } }; 68*0Sstevel@tonic-gate} 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate# And these are so that GetOptsOO knows they take options: 71*0Sstevel@tonic-gatesub opt_f_with { shift->_elem('opt_f', @_) } 72*0Sstevel@tonic-gatesub opt_q_with { shift->_elem('opt_q', @_) } 73*0Sstevel@tonic-gatesub opt_d_with { shift->_elem('opt_d', @_) } 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gatesub opt_w_with { # Specify an option for the formatter subclass 76*0Sstevel@tonic-gate my($self, $value) = @_; 77*0Sstevel@tonic-gate if($value =~ m/^([-_a-zA-Z][-_a-zA-Z0-9]*)(?:[=\:](.*?))?$/s) { 78*0Sstevel@tonic-gate my $option = $1; 79*0Sstevel@tonic-gate my $option_value = defined($2) ? $2 : "TRUE"; 80*0Sstevel@tonic-gate $option =~ tr/\-/_/s; # tolerate "foo-bar" for "foo_bar" 81*0Sstevel@tonic-gate $self->add_formatter_option( $option, $option_value ); 82*0Sstevel@tonic-gate } else { 83*0Sstevel@tonic-gate warn "\"$value\" isn't a good formatter option name. I'm ignoring it!\n"; 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate return; 86*0Sstevel@tonic-gate} 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gatesub opt_M_with { # specify formatter class name(s) 89*0Sstevel@tonic-gate my($self, $classes) = @_; 90*0Sstevel@tonic-gate return unless defined $classes and length $classes; 91*0Sstevel@tonic-gate DEBUG > 4 and print "Considering new formatter classes -M$classes\n"; 92*0Sstevel@tonic-gate my @classes_to_add; 93*0Sstevel@tonic-gate foreach my $classname (split m/[,;]+/s, $classes) { 94*0Sstevel@tonic-gate next unless $classname =~ m/\S/; 95*0Sstevel@tonic-gate if( $classname =~ m/^(\w+(::\w+)+)$/s ) { 96*0Sstevel@tonic-gate # A mildly restrictive concept of what modulenames are valid. 97*0Sstevel@tonic-gate push @classes_to_add, $1; # untaint 98*0Sstevel@tonic-gate } else { 99*0Sstevel@tonic-gate warn "\"$classname\" isn't a valid classname. Ignoring.\n"; 100*0Sstevel@tonic-gate } 101*0Sstevel@tonic-gate } 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate unshift @{ $self->{'formatter_classes'} }, @classes_to_add; 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate DEBUG > 3 and print( 106*0Sstevel@tonic-gate "Adding @classes_to_add to the list of formatter classes, " 107*0Sstevel@tonic-gate . "making them @{ $self->{'formatter_classes'} }.\n" 108*0Sstevel@tonic-gate ); 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate return; 111*0Sstevel@tonic-gate} 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gatesub opt_V { # report version and exit 114*0Sstevel@tonic-gate print join '', 115*0Sstevel@tonic-gate "Perldoc v$VERSION, under perl v$] for $^O", 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate (defined(&Win32::BuildNumber) and defined &Win32::BuildNumber()) 118*0Sstevel@tonic-gate ? (" (win32 build ", &Win32::BuildNumber(), ")") : (), 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate (chr(65) eq 'A') ? () : " (non-ASCII)", 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate "\n", 123*0Sstevel@tonic-gate ; 124*0Sstevel@tonic-gate exit; 125*0Sstevel@tonic-gate} 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gatesub opt_t { # choose plaintext as output format 128*0Sstevel@tonic-gate my $self = shift; 129*0Sstevel@tonic-gate $self->opt_o_with('text') if @_ and $_[0]; 130*0Sstevel@tonic-gate return $self->_elem('opt_t', @_); 131*0Sstevel@tonic-gate} 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gatesub opt_u { # choose raw pod as output format 134*0Sstevel@tonic-gate my $self = shift; 135*0Sstevel@tonic-gate $self->opt_o_with('pod') if @_ and $_[0]; 136*0Sstevel@tonic-gate return $self->_elem('opt_u', @_); 137*0Sstevel@tonic-gate} 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gatesub opt_n_with { 140*0Sstevel@tonic-gate # choose man as the output format, and specify the proggy to run 141*0Sstevel@tonic-gate my $self = shift; 142*0Sstevel@tonic-gate $self->opt_o_with('man') if @_ and $_[0]; 143*0Sstevel@tonic-gate $self->_elem('opt_n', @_); 144*0Sstevel@tonic-gate} 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gatesub opt_o_with { # "o" for output format 147*0Sstevel@tonic-gate my($self, $rest) = @_; 148*0Sstevel@tonic-gate return unless defined $rest and length $rest; 149*0Sstevel@tonic-gate if($rest =~ m/^(\w+)$/s) { 150*0Sstevel@tonic-gate $rest = $1; #untaint 151*0Sstevel@tonic-gate } else { 152*0Sstevel@tonic-gate warn "\"$rest\" isn't a valid output format. Skipping.\n"; 153*0Sstevel@tonic-gate return; 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate $self->aside("Noting \"$rest\" as desired output format...\n"); 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate # Figure out what class(es) that could actually mean... 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate my @classes; 161*0Sstevel@tonic-gate foreach my $prefix ("Pod::Perldoc::To", "Pod::Simple::", "Pod::") { 162*0Sstevel@tonic-gate # Messy but smart: 163*0Sstevel@tonic-gate foreach my $stem ( 164*0Sstevel@tonic-gate $rest, # Yes, try it first with the given capitalization 165*0Sstevel@tonic-gate "\L$rest", "\L\u$rest", "\U$rest" # And then try variations 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate ) { 168*0Sstevel@tonic-gate push @classes, $prefix . $stem; 169*0Sstevel@tonic-gate #print "Considering $prefix$stem\n"; 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate # Tidier, but misses too much: 173*0Sstevel@tonic-gate #push @classes, $prefix . ucfirst(lc($rest)); 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate $self->opt_M_with( join ";", @classes ); 176*0Sstevel@tonic-gate return; 177*0Sstevel@tonic-gate} 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate########################################################################### 180*0Sstevel@tonic-gate# % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gatesub run { # to be called by the "perldoc" executable 183*0Sstevel@tonic-gate my $class = shift; 184*0Sstevel@tonic-gate if(DEBUG > 3) { 185*0Sstevel@tonic-gate print "Parameters to $class\->run:\n"; 186*0Sstevel@tonic-gate my @x = @_; 187*0Sstevel@tonic-gate while(@x) { 188*0Sstevel@tonic-gate $x[1] = '<undef>' unless defined $x[1]; 189*0Sstevel@tonic-gate $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY'; 190*0Sstevel@tonic-gate print " [$x[0]] => [$x[1]]\n"; 191*0Sstevel@tonic-gate splice @x,0,2; 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate print "\n"; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate return $class -> new(@_) -> process() || 0; 196*0Sstevel@tonic-gate} 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate# % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % 199*0Sstevel@tonic-gate########################################################################### 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gatesub new { # yeah, nothing fancy 202*0Sstevel@tonic-gate my $class = shift; 203*0Sstevel@tonic-gate my $new = bless {@_}, (ref($class) || $class); 204*0Sstevel@tonic-gate DEBUG > 1 and print "New $class object $new\n"; 205*0Sstevel@tonic-gate $new->init(); 206*0Sstevel@tonic-gate $new; 207*0Sstevel@tonic-gate} 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate#.......................................................................... 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gatesub aside { # If we're in -v or DEBUG mode, say this. 212*0Sstevel@tonic-gate my $self = shift; 213*0Sstevel@tonic-gate if( DEBUG or $self->opt_v ) { 214*0Sstevel@tonic-gate my $out = join( '', 215*0Sstevel@tonic-gate DEBUG ? do { 216*0Sstevel@tonic-gate my $callsub = (caller(1))[3]; 217*0Sstevel@tonic-gate my $package = quotemeta(__PACKAGE__ . '::'); 218*0Sstevel@tonic-gate $callsub =~ s/^$package/'/os; 219*0Sstevel@tonic-gate # the o is justified, as $package really won't change. 220*0Sstevel@tonic-gate $callsub . ": "; 221*0Sstevel@tonic-gate } : '', 222*0Sstevel@tonic-gate @_, 223*0Sstevel@tonic-gate ); 224*0Sstevel@tonic-gate if(DEBUG) { print $out } else { print STDERR $out } 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate return; 227*0Sstevel@tonic-gate} 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate#.......................................................................... 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gatesub usage { 232*0Sstevel@tonic-gate my $self = shift; 233*0Sstevel@tonic-gate warn "@_\n" if @_; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate # Erase evidence of previous errors (if any), so exit status is simple. 236*0Sstevel@tonic-gate $! = 0; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate die <<EOF; 239*0Sstevel@tonic-gateperldoc [options] PageName|ModuleName|ProgramName... 240*0Sstevel@tonic-gateperldoc [options] -f BuiltinFunction 241*0Sstevel@tonic-gateperldoc [options] -q FAQRegex 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gateOptions: 244*0Sstevel@tonic-gate -h Display this help message 245*0Sstevel@tonic-gate -V report version 246*0Sstevel@tonic-gate -r Recursive search (slow) 247*0Sstevel@tonic-gate -i Ignore case 248*0Sstevel@tonic-gate -t Display pod using pod2text instead of pod2man and nroff 249*0Sstevel@tonic-gate (-t is the default on win32 unless -n is specified) 250*0Sstevel@tonic-gate -u Display unformatted pod text 251*0Sstevel@tonic-gate -m Display module's file in its entirety 252*0Sstevel@tonic-gate -n Specify replacement for nroff 253*0Sstevel@tonic-gate -l Display the module's file name 254*0Sstevel@tonic-gate -F Arguments are file names, not modules 255*0Sstevel@tonic-gate -v Verbosely describe what's going on 256*0Sstevel@tonic-gate -T Send output to STDOUT without any pager 257*0Sstevel@tonic-gate -d output_filename_to_send_to 258*0Sstevel@tonic-gate -o output_format_name 259*0Sstevel@tonic-gate -M FormatterModuleNameToUse 260*0Sstevel@tonic-gate -w formatter_option:option_value 261*0Sstevel@tonic-gate -X use index if present (looks for pod.idx at $Config{archlib}) 262*0Sstevel@tonic-gate -q Search the text of questions (not answers) in perlfaq[1-9] 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gatePageName|ModuleName... 265*0Sstevel@tonic-gate is the name of a piece of documentation that you want to look at. You 266*0Sstevel@tonic-gate may either give a descriptive name of the page (as in the case of 267*0Sstevel@tonic-gate `perlfunc') the name of a module, either like `Term::Info' or like 268*0Sstevel@tonic-gate `Term/Info', or the name of a program, like `perldoc'. 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gateBuiltinFunction 271*0Sstevel@tonic-gate is the name of a perl function. Will extract documentation from 272*0Sstevel@tonic-gate `perlfunc'. 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gateFAQRegex 275*0Sstevel@tonic-gate is a regex. Will search perlfaq[1-9] for and extract any 276*0Sstevel@tonic-gate questions that match. 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gateAny switches in the PERLDOC environment variable will be used before the 279*0Sstevel@tonic-gatecommand line arguments. The optional pod index file contains a list of 280*0Sstevel@tonic-gatefilenames, one per line. 281*0Sstevel@tonic-gate [Perldoc v$VERSION] 282*0Sstevel@tonic-gateEOF 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate} 285*0Sstevel@tonic-gate 286*0Sstevel@tonic-gate#.......................................................................... 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gatesub usage_brief { 289*0Sstevel@tonic-gate my $me = $0; # Editing $0 is unportable 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate $me =~ s,.*[/\\],,; # get basename 292*0Sstevel@tonic-gate 293*0Sstevel@tonic-gate die <<"EOUSAGE"; 294*0Sstevel@tonic-gateUsage: $me [-h] [-V] [-r] [-i] [-v] [-t] [-u] [-m] [-n nroffer_program] [-l] [-T] [-d output_filename] [-o output_format] [-M FormatterModuleNameToUse] [-w formatter_option:option_value] [-F] [-X] PageName|ModuleName|ProgramName 295*0Sstevel@tonic-gate $me -f PerlFunc 296*0Sstevel@tonic-gate $me -q FAQKeywords 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gateThe -h option prints more help. Also try "perldoc perldoc" to get 299*0Sstevel@tonic-gateacquainted with the system. [Perldoc v$VERSION] 300*0Sstevel@tonic-gateEOUSAGE 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate} 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate#.......................................................................... 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gatesub pagers { @{ shift->{'pagers'} } } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate#.......................................................................... 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gatesub _elem { # handy scalar meta-accessor: shift->_elem("foo", @_) 311*0Sstevel@tonic-gate if(@_ > 2) { return $_[0]{ $_[1] } = $_[2] } 312*0Sstevel@tonic-gate else { return $_[0]{ $_[1] } } 313*0Sstevel@tonic-gate} 314*0Sstevel@tonic-gate#.......................................................................... 315*0Sstevel@tonic-gate########################################################################### 316*0Sstevel@tonic-gate# 317*0Sstevel@tonic-gate# Init formatter switches, and start it off with __bindir and all that 318*0Sstevel@tonic-gate# other stuff that ToMan.pm needs. 319*0Sstevel@tonic-gate# 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gatesub init { 322*0Sstevel@tonic-gate my $self = shift; 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate # Make sure creat()s are neither too much nor too little 325*0Sstevel@tonic-gate eval { umask(0077) }; # doubtless someone has no mask 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate $self->{'args'} ||= \@ARGV; 328*0Sstevel@tonic-gate $self->{'found'} ||= []; 329*0Sstevel@tonic-gate $self->{'temp_file_list'} ||= []; 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate $self->{'target'} = undef; 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate $self->init_formatter_class_list; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate $self->{'pagers' } = [@Pagers] unless exists $self->{'pagers'}; 337*0Sstevel@tonic-gate $self->{'bindir' } = $Bindir unless exists $self->{'bindir'}; 338*0Sstevel@tonic-gate $self->{'pod2man'} = $Pod2man unless exists $self->{'pod2man'}; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate push @{ $self->{'formatter_switches'} = [] }, ( 341*0Sstevel@tonic-gate # Yeah, we could use a hashref, but maybe there's some class where options 342*0Sstevel@tonic-gate # have to be ordered; so we'll use an arrayref. 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate [ '__bindir' => $self->{'bindir' } ], 345*0Sstevel@tonic-gate [ '__pod2man' => $self->{'pod2man'} ], 346*0Sstevel@tonic-gate ); 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate DEBUG > 3 and printf "Formatter switches now: [%s]\n", 349*0Sstevel@tonic-gate join ' ', map "[@$_]", @{ $self->{'formatter_switches'} }; 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate return; 352*0Sstevel@tonic-gate} 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate#.......................................................................... 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gatesub init_formatter_class_list { 357*0Sstevel@tonic-gate my $self = shift; 358*0Sstevel@tonic-gate $self->{'formatter_classes'} ||= []; 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate # Remember, no switches have been read yet, when 361*0Sstevel@tonic-gate # we've started this routine. 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate $self->opt_M_with('Pod::Perldoc::ToPod'); # the always-there fallthru 364*0Sstevel@tonic-gate $self->opt_o_with('text'); 365*0Sstevel@tonic-gate $self->opt_o_with('man') unless IS_MSWin32 || IS_Dos 366*0Sstevel@tonic-gate || !($ENV{TERM} && ( 367*0Sstevel@tonic-gate ($ENV{TERM} || '') !~ /dumb|emacs|none|unknown/i 368*0Sstevel@tonic-gate )); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate return; 371*0Sstevel@tonic-gate} 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate#.......................................................................... 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gatesub process { 376*0Sstevel@tonic-gate # if this ever returns, its retval will be used for exit(RETVAL) 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate my $self = shift; 379*0Sstevel@tonic-gate DEBUG > 1 and print " Beginning process.\n"; 380*0Sstevel@tonic-gate DEBUG > 1 and print " Args: @{$self->{'args'}}\n\n"; 381*0Sstevel@tonic-gate if(DEBUG > 3) { 382*0Sstevel@tonic-gate print "Object contents:\n"; 383*0Sstevel@tonic-gate my @x = %$self; 384*0Sstevel@tonic-gate while(@x) { 385*0Sstevel@tonic-gate $x[1] = '<undef>' unless defined $x[1]; 386*0Sstevel@tonic-gate $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY'; 387*0Sstevel@tonic-gate print " [$x[0]] => [$x[1]]\n"; 388*0Sstevel@tonic-gate splice @x,0,2; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate print "\n"; 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate # TODO: make it deal with being invoked as various different things 394*0Sstevel@tonic-gate # such as perlfaq". 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate return $self->usage_brief unless @{ $self->{'args'} }; 397*0Sstevel@tonic-gate $self->pagers_guessing; 398*0Sstevel@tonic-gate $self->options_reading; 399*0Sstevel@tonic-gate $self->aside(sprintf "$0 => %s v%s\n", ref($self), $self->VERSION); 400*0Sstevel@tonic-gate $self->drop_privs_maybe; 401*0Sstevel@tonic-gate $self->options_processing; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate # Hm, we have @pages and @found, but we only really act on one 404*0Sstevel@tonic-gate # file per call, with the exception of the opt_q hack, and with 405*0Sstevel@tonic-gate # -l things 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate $self->aside("\n"); 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate my @pages; 410*0Sstevel@tonic-gate $self->{'pages'} = \@pages; 411*0Sstevel@tonic-gate if( $self->opt_f) { @pages = ("perlfunc") } 412*0Sstevel@tonic-gate elsif( $self->opt_q) { @pages = ("perlfaq1" .. "perlfaq9") } 413*0Sstevel@tonic-gate else { @pages = @{$self->{'args'}}; 414*0Sstevel@tonic-gate # @pages = __FILE__ 415*0Sstevel@tonic-gate # if @pages == 1 and $pages[0] eq 'perldoc'; 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate 418*0Sstevel@tonic-gate return $self->usage_brief unless @pages; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate $self->find_good_formatter_class(); 421*0Sstevel@tonic-gate $self->formatter_sanity_check(); 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate $self->maybe_diddle_INC(); 424*0Sstevel@tonic-gate # for when we're apparently in a module or extension directory 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate my @found = $self->grand_search_init(\@pages); 427*0Sstevel@tonic-gate exit (IS_VMS ? 98962 : 1) unless @found; 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate if ($self->opt_l) { 430*0Sstevel@tonic-gate DEBUG and print "We're in -l mode, so byebye after this:\n"; 431*0Sstevel@tonic-gate print join("\n", @found), "\n"; 432*0Sstevel@tonic-gate return; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate $self->tweak_found_pathnames(\@found); 436*0Sstevel@tonic-gate $self->assert_closing_stdout; 437*0Sstevel@tonic-gate return $self->page_module_file(@found) if $self->opt_m; 438*0Sstevel@tonic-gate DEBUG > 2 and print "Found: [@found]\n"; 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate return $self->render_and_page(\@found); 441*0Sstevel@tonic-gate} 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate#.......................................................................... 444*0Sstevel@tonic-gate{ 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gatemy( %class_seen, %class_loaded ); 447*0Sstevel@tonic-gatesub find_good_formatter_class { 448*0Sstevel@tonic-gate my $self = $_[0]; 449*0Sstevel@tonic-gate my @class_list = @{ $self->{'formatter_classes'} || [] }; 450*0Sstevel@tonic-gate die "WHAT? Nothing in the formatter class list!?" unless @class_list; 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate my $good_class_found; 453*0Sstevel@tonic-gate foreach my $c (@class_list) { 454*0Sstevel@tonic-gate DEBUG > 4 and print "Trying to load $c...\n"; 455*0Sstevel@tonic-gate if($class_loaded{$c}) { 456*0Sstevel@tonic-gate DEBUG > 4 and print "OK, the already-loaded $c it is!\n"; 457*0Sstevel@tonic-gate $good_class_found = $c; 458*0Sstevel@tonic-gate last; 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate if($class_seen{$c}) { 462*0Sstevel@tonic-gate DEBUG > 4 and print 463*0Sstevel@tonic-gate "I've tried $c before, and it's no good. Skipping.\n"; 464*0Sstevel@tonic-gate next; 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate $class_seen{$c} = 1; 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate if( $c->can('parse_from_file') ) { 470*0Sstevel@tonic-gate DEBUG > 4 and print 471*0Sstevel@tonic-gate "Interesting, the formatter class $c is already loaded!\n"; 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate } elsif( 474*0Sstevel@tonic-gate (IS_VMS or IS_MSWin32 or IS_Dos or IS_OS2) 475*0Sstevel@tonic-gate # the alway case-insensitive fs's 476*0Sstevel@tonic-gate and $class_seen{lc("~$c")}++ 477*0Sstevel@tonic-gate ) { 478*0Sstevel@tonic-gate DEBUG > 4 and print 479*0Sstevel@tonic-gate "We already used something quite like \"\L$c\E\", so no point using $c\n"; 480*0Sstevel@tonic-gate # This avoids redefining the package. 481*0Sstevel@tonic-gate } else { 482*0Sstevel@tonic-gate DEBUG > 4 and print "Trying to eval 'require $c'...\n"; 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate local $^W = $^W; 485*0Sstevel@tonic-gate if(DEBUG() or $self->opt_v) { 486*0Sstevel@tonic-gate # feh, let 'em see it 487*0Sstevel@tonic-gate } else { 488*0Sstevel@tonic-gate $^W = 0; 489*0Sstevel@tonic-gate # The average user just has no reason to be seeing 490*0Sstevel@tonic-gate # $^W-suppressable warnings from the the require! 491*0Sstevel@tonic-gate } 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate eval "require $c"; 494*0Sstevel@tonic-gate if($@) { 495*0Sstevel@tonic-gate DEBUG > 4 and print "Couldn't load $c: $!\n"; 496*0Sstevel@tonic-gate next; 497*0Sstevel@tonic-gate } 498*0Sstevel@tonic-gate } 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate if( $c->can('parse_from_file') ) { 501*0Sstevel@tonic-gate DEBUG > 4 and print "Settling on $c\n"; 502*0Sstevel@tonic-gate my $v = $c->VERSION; 503*0Sstevel@tonic-gate $v = ( defined $v and length $v ) ? " version $v" : ''; 504*0Sstevel@tonic-gate $self->aside("Formatter class $c$v successfully loaded!\n"); 505*0Sstevel@tonic-gate $good_class_found = $c; 506*0Sstevel@tonic-gate last; 507*0Sstevel@tonic-gate } else { 508*0Sstevel@tonic-gate DEBUG > 4 and print "Class $c isn't a formatter?! Skipping.\n"; 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate die "Can't find any loadable formatter class in @class_list?!\nAborting" 513*0Sstevel@tonic-gate unless $good_class_found; 514*0Sstevel@tonic-gate 515*0Sstevel@tonic-gate $self->{'formatter_class'} = $good_class_found; 516*0Sstevel@tonic-gate $self->aside("Will format with the class $good_class_found\n"); 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate return; 519*0Sstevel@tonic-gate} 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate} 522*0Sstevel@tonic-gate#.......................................................................... 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gatesub formatter_sanity_check { 525*0Sstevel@tonic-gate my $self = shift; 526*0Sstevel@tonic-gate my $formatter_class = $self->{'formatter_class'} 527*0Sstevel@tonic-gate || die "NO FORMATTER CLASS YET!?"; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate if(!$self->opt_T # so -T can FORCE sending to STDOUT 530*0Sstevel@tonic-gate and $formatter_class->can('is_pageable') 531*0Sstevel@tonic-gate and !$formatter_class->is_pageable 532*0Sstevel@tonic-gate and !$formatter_class->can('page_for_perldoc') 533*0Sstevel@tonic-gate ) { 534*0Sstevel@tonic-gate my $ext = 535*0Sstevel@tonic-gate ($formatter_class->can('output_extension') 536*0Sstevel@tonic-gate && $formatter_class->output_extension 537*0Sstevel@tonic-gate ) || ''; 538*0Sstevel@tonic-gate $ext = ".$ext" if length $ext; 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate die 541*0Sstevel@tonic-gate "When using Perldoc to format with $formatter_class, you have to\n" 542*0Sstevel@tonic-gate . "specify -T or -dsomefile$ext\n" 543*0Sstevel@tonic-gate . "See `perldoc perldoc' for more information on those switches.\n" 544*0Sstevel@tonic-gate ; 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate} 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate#.......................................................................... 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gatesub render_and_page { 551*0Sstevel@tonic-gate my($self, $found_list) = @_; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate $self->maybe_generate_dynamic_pod($found_list); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate my($out, $formatter) = $self->render_findings($found_list); 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate if($self->opt_d) { 558*0Sstevel@tonic-gate printf "Perldoc (%s) output saved to %s\n", 559*0Sstevel@tonic-gate $self->{'formatter_class'} || ref($self), 560*0Sstevel@tonic-gate $out; 561*0Sstevel@tonic-gate print "But notice that it's 0 bytes long!\n" unless -s $out; 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate } elsif( # Allow the formatter to "page" itself, if it wants. 565*0Sstevel@tonic-gate $formatter->can('page_for_perldoc') 566*0Sstevel@tonic-gate and do { 567*0Sstevel@tonic-gate $self->aside("Going to call $formatter\->page_for_perldoc(\"$out\")\n"); 568*0Sstevel@tonic-gate if( $formatter->page_for_perldoc($out, $self) ) { 569*0Sstevel@tonic-gate $self->aside("page_for_perldoc returned true, so NOT paging with $self.\n"); 570*0Sstevel@tonic-gate 1; 571*0Sstevel@tonic-gate } else { 572*0Sstevel@tonic-gate $self->aside("page_for_perldoc returned false, so paging with $self instead.\n"); 573*0Sstevel@tonic-gate ''; 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate } 576*0Sstevel@tonic-gate ) { 577*0Sstevel@tonic-gate # Do nothing, since the formatter has "paged" it for itself. 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate } else { 580*0Sstevel@tonic-gate # Page it normally (internally) 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate if( -s $out ) { # Usual case: 583*0Sstevel@tonic-gate $self->page($out, $self->{'output_to_stdout'}, $self->pagers); 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate } else { 586*0Sstevel@tonic-gate # Odd case: 587*0Sstevel@tonic-gate $self->aside("Skipping $out (from $$found_list[0] " 588*0Sstevel@tonic-gate . "via $$self{'formatter_class'}) as it is 0-length.\n"); 589*0Sstevel@tonic-gate 590*0Sstevel@tonic-gate push @{ $self->{'temp_file_list'} }, $out; 591*0Sstevel@tonic-gate $self->unlink_if_temp_file($out); 592*0Sstevel@tonic-gate } 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate $self->after_rendering(); # any extra cleanup or whatever 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate return; 598*0Sstevel@tonic-gate} 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate#.......................................................................... 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gatesub options_reading { 603*0Sstevel@tonic-gate my $self = shift; 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate if( defined $ENV{"PERLDOC"} and length $ENV{"PERLDOC"} ) { 606*0Sstevel@tonic-gate require Text::ParseWords; 607*0Sstevel@tonic-gate $self->aside("Noting env PERLDOC setting of $ENV{'PERLDOC'}\n"); 608*0Sstevel@tonic-gate # Yes, appends to the beginning 609*0Sstevel@tonic-gate unshift @{ $self->{'args'} }, 610*0Sstevel@tonic-gate Text::ParseWords::shellwords( $ENV{"PERLDOC"} ) 611*0Sstevel@tonic-gate ; 612*0Sstevel@tonic-gate DEBUG > 1 and print " Args now: @{$self->{'args'}}\n\n"; 613*0Sstevel@tonic-gate } else { 614*0Sstevel@tonic-gate DEBUG > 1 and print " Okay, no PERLDOC setting in ENV.\n"; 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate DEBUG > 1 618*0Sstevel@tonic-gate and print " Args right before switch processing: @{$self->{'args'}}\n"; 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate Pod::Perldoc::GetOptsOO::getopts( $self, $self->{'args'}, 'YES' ) 621*0Sstevel@tonic-gate or return $self->usage; 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate DEBUG > 1 624*0Sstevel@tonic-gate and print " Args after switch processing: @{$self->{'args'}}\n"; 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate return $self->usage if $self->opt_h; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate return; 629*0Sstevel@tonic-gate} 630*0Sstevel@tonic-gate 631*0Sstevel@tonic-gate#.......................................................................... 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gatesub options_processing { 634*0Sstevel@tonic-gate my $self = shift; 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate if ($self->opt_X) { 637*0Sstevel@tonic-gate my $podidx = "$Config{'archlib'}/pod.idx"; 638*0Sstevel@tonic-gate $podidx = "" unless -f $podidx && -r _ && -M _ <= 7; 639*0Sstevel@tonic-gate $self->{'podidx'} = $podidx; 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate $self->{'output_to_stdout'} = 1 if $self->opt_T or ! -t STDOUT; 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate $self->options_sanity; 645*0Sstevel@tonic-gate 646*0Sstevel@tonic-gate $self->opt_n("nroff") unless $self->opt_n; 647*0Sstevel@tonic-gate $self->add_formatter_option( '__nroffer' => $self->opt_n ); 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate return; 650*0Sstevel@tonic-gate} 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate#.......................................................................... 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gatesub options_sanity { 655*0Sstevel@tonic-gate my $self = shift; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate # The opts-counting stuff interacts quite badly with 658*0Sstevel@tonic-gate # the $ENV{"PERLDOC"} stuff. I.e., if I have $ENV{"PERLDOC"} 659*0Sstevel@tonic-gate # set to -t, and I specify -u on the command line, I don't want 660*0Sstevel@tonic-gate # to be hectored at that -u and -t don't make sense together. 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate #my $opts = grep $_ && 1, # yes, the count of the set ones 663*0Sstevel@tonic-gate # $self->opt_t, $self->opt_u, $self->opt_m, $self->opt_l 664*0Sstevel@tonic-gate #; 665*0Sstevel@tonic-gate # 666*0Sstevel@tonic-gate #$self->usage("only one of -t, -u, -m or -l") if $opts > 1; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate 669*0Sstevel@tonic-gate # Any sanity-checking need doing here? 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate return; 672*0Sstevel@tonic-gate} 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate#.......................................................................... 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gatesub grand_search_init { 677*0Sstevel@tonic-gate my($self, $pages, @found) = @_; 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate foreach (@$pages) { 680*0Sstevel@tonic-gate if ($self->{'podidx'} && open(PODIDX, $self->{'podidx'})) { 681*0Sstevel@tonic-gate my $searchfor = catfile split '::', $_; 682*0Sstevel@tonic-gate $self->aside( "Searching for '$searchfor' in $self->{'podidx'}\n" ); 683*0Sstevel@tonic-gate local $_; 684*0Sstevel@tonic-gate while (<PODIDX>) { 685*0Sstevel@tonic-gate chomp; 686*0Sstevel@tonic-gate push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?\z,i; 687*0Sstevel@tonic-gate } 688*0Sstevel@tonic-gate close(PODIDX) or die "Can't close $$self{'podidx'}: $!"; 689*0Sstevel@tonic-gate next; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate $self->aside( "Searching for $_\n" ); 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate if ($self->opt_F) { 695*0Sstevel@tonic-gate next unless -r; 696*0Sstevel@tonic-gate push @found, $_ if $self->opt_m or $self->containspod($_); 697*0Sstevel@tonic-gate next; 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate # We must look both in @INC for library modules and in $bindir 701*0Sstevel@tonic-gate # for executables, like h2xs or perldoc itself. 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate my @searchdirs = ($self->{'bindir'}, @INC); 704*0Sstevel@tonic-gate unless ($self->opt_m) { 705*0Sstevel@tonic-gate if (IS_VMS) { 706*0Sstevel@tonic-gate my($i,$trn); 707*0Sstevel@tonic-gate for ($i = 0; $trn = $ENV{'DCL$PATH;'.$i}; $i++) { 708*0Sstevel@tonic-gate push(@searchdirs,$trn); 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate push(@searchdirs,'perl_root:[lib.pod]') # installed pods 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate else { 713*0Sstevel@tonic-gate push(@searchdirs, grep(-d, split($Config{path_sep}, 714*0Sstevel@tonic-gate $ENV{'PATH'}))); 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate } 717*0Sstevel@tonic-gate my @files = $self->searchfor(0,$_,@searchdirs); 718*0Sstevel@tonic-gate if (@files) { 719*0Sstevel@tonic-gate $self->aside( "Found as @files\n" ); 720*0Sstevel@tonic-gate } 721*0Sstevel@tonic-gate else { 722*0Sstevel@tonic-gate # no match, try recursive search 723*0Sstevel@tonic-gate @searchdirs = grep(!/^\.\z/s,@INC); 724*0Sstevel@tonic-gate @files= $self->searchfor(1,$_,@searchdirs) if $self->opt_r; 725*0Sstevel@tonic-gate if (@files) { 726*0Sstevel@tonic-gate $self->aside( "Loosely found as @files\n" ); 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate else { 729*0Sstevel@tonic-gate print STDERR "No " . 730*0Sstevel@tonic-gate ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n"; 731*0Sstevel@tonic-gate if ( @{ $self->{'found'} } ) { 732*0Sstevel@tonic-gate print STDERR "However, try\n"; 733*0Sstevel@tonic-gate for my $dir (@{ $self->{'found'} }) { 734*0Sstevel@tonic-gate opendir(DIR, $dir) or die "opendir $dir: $!"; 735*0Sstevel@tonic-gate while (my $file = readdir(DIR)) { 736*0Sstevel@tonic-gate next if ($file =~ /^\./s); 737*0Sstevel@tonic-gate $file =~ s/\.(pm|pod)\z//; # XXX: badfs 738*0Sstevel@tonic-gate print STDERR "\tperldoc $_\::$file\n"; 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate closedir(DIR) or die "closedir $dir: $!"; 741*0Sstevel@tonic-gate } 742*0Sstevel@tonic-gate } 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate push(@found,@files); 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate return @found; 748*0Sstevel@tonic-gate} 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate#.......................................................................... 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gatesub maybe_generate_dynamic_pod { 753*0Sstevel@tonic-gate my($self, $found_things) = @_; 754*0Sstevel@tonic-gate my @dynamic_pod; 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate $self->search_perlfunc($found_things, \@dynamic_pod) if $self->opt_f; 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate $self->search_perlfaqs($found_things, \@dynamic_pod) if $self->opt_q; 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate if( ! $self->opt_f and ! $self->opt_q ) { 761*0Sstevel@tonic-gate DEBUG > 4 and print "That's a non-dynamic pod search.\n"; 762*0Sstevel@tonic-gate } elsif ( @dynamic_pod ) { 763*0Sstevel@tonic-gate $self->aside("Hm, I found some Pod from that search!\n"); 764*0Sstevel@tonic-gate my ($buffd, $buffer) = $self->new_tempfile('pod', 'dyn'); 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate push @{ $self->{'temp_file_list'} }, $buffer; 767*0Sstevel@tonic-gate # I.e., it MIGHT be deleted at the end. 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate my $in_list = $self->opt_f; 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate print $buffd "=over 8\n\n" if $in_list; 772*0Sstevel@tonic-gate print $buffd @dynamic_pod or die "Can't print $buffer: $!"; 773*0Sstevel@tonic-gate print $buffd "=back\n" if $in_list; 774*0Sstevel@tonic-gate 775*0Sstevel@tonic-gate close $buffd or die "Can't close $buffer: $!"; 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate @$found_things = $buffer; 778*0Sstevel@tonic-gate # Yes, so found_things never has more than one thing in 779*0Sstevel@tonic-gate # it, by time we leave here 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate $self->add_formatter_option('__filter_nroff' => 1); 782*0Sstevel@tonic-gate 783*0Sstevel@tonic-gate } else { 784*0Sstevel@tonic-gate @$found_things = (); 785*0Sstevel@tonic-gate $self->aside("I found no Pod from that search!\n"); 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate return; 789*0Sstevel@tonic-gate} 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate#.......................................................................... 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gatesub add_formatter_option { # $self->add_formatter_option('key' => 'value'); 794*0Sstevel@tonic-gate my $self = shift; 795*0Sstevel@tonic-gate push @{ $self->{'formatter_switches'} }, [ @_ ] if @_; 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate DEBUG > 3 and printf "Formatter switches now: [%s]\n", 798*0Sstevel@tonic-gate join ' ', map "[@$_]", @{ $self->{'formatter_switches'} }; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate return; 801*0Sstevel@tonic-gate} 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate#.......................................................................... 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gatesub search_perlfunc { 806*0Sstevel@tonic-gate my($self, $found_things, $pod) = @_; 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate DEBUG > 2 and print "Search: @$found_things\n"; 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate my $perlfunc = shift @$found_things; 811*0Sstevel@tonic-gate open(PFUNC, "<", $perlfunc) # "Funk is its own reward" 812*0Sstevel@tonic-gate or die("Can't open $perlfunc: $!"); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate # Functions like -r, -e, etc. are listed under `-X'. 815*0Sstevel@tonic-gate my $search_re = ($self->opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/) 816*0Sstevel@tonic-gate ? '(?:I<)?-X' : quotemeta($self->opt_f) ; 817*0Sstevel@tonic-gate 818*0Sstevel@tonic-gate DEBUG > 2 and 819*0Sstevel@tonic-gate print "Going to perlfunc-scan for $search_re in $perlfunc\n"; 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate # Skip introduction 822*0Sstevel@tonic-gate local $_; 823*0Sstevel@tonic-gate while (<PFUNC>) { 824*0Sstevel@tonic-gate last if /^=head2 Alphabetical Listing of Perl Functions/; 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate # Look for our function 828*0Sstevel@tonic-gate my $found = 0; 829*0Sstevel@tonic-gate my $inlist = 0; 830*0Sstevel@tonic-gate while (<PFUNC>) { # "The Mothership Connection is here!" 831*0Sstevel@tonic-gate if ( m/^=item\s+$search_re\b/ ) { 832*0Sstevel@tonic-gate $found = 1; 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate elsif (/^=item/) { 835*0Sstevel@tonic-gate last if $found > 1 and not $inlist; 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate next unless $found; 838*0Sstevel@tonic-gate if (/^=over/) { 839*0Sstevel@tonic-gate ++$inlist; 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate elsif (/^=back/) { 842*0Sstevel@tonic-gate --$inlist; 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate push @$pod, $_; 845*0Sstevel@tonic-gate ++$found if /^\w/; # found descriptive text 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate if (!@$pod) { 848*0Sstevel@tonic-gate die sprintf 849*0Sstevel@tonic-gate "No documentation for perl function `%s' found\n", 850*0Sstevel@tonic-gate $self->opt_f 851*0Sstevel@tonic-gate ; 852*0Sstevel@tonic-gate } 853*0Sstevel@tonic-gate close PFUNC or die "Can't open $perlfunc: $!"; 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate return; 856*0Sstevel@tonic-gate} 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate#.......................................................................... 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gatesub search_perlfaqs { 861*0Sstevel@tonic-gate my( $self, $found_things, $pod) = @_; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate my $found = 0; 864*0Sstevel@tonic-gate my %found_in; 865*0Sstevel@tonic-gate my $search_key = $self->opt_q; 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate my $rx = eval { qr/$search_key/ } 868*0Sstevel@tonic-gate or die <<EOD; 869*0Sstevel@tonic-gateInvalid regular expression '$search_key' given as -q pattern: 870*0Sstevel@tonic-gate$@ 871*0Sstevel@tonic-gateDid you mean \\Q$search_key ? 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gateEOD 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate local $_; 876*0Sstevel@tonic-gate foreach my $file (@$found_things) { 877*0Sstevel@tonic-gate die "invalid file spec: $!" if $file =~ /[<>|]/; 878*0Sstevel@tonic-gate open(INFAQ, "<", $file) # XXX 5.6ism 879*0Sstevel@tonic-gate or die "Can't read-open $file: $!\nAborting"; 880*0Sstevel@tonic-gate while (<INFAQ>) { 881*0Sstevel@tonic-gate if ( m/^=head2\s+.*(?:$search_key)/i ) { 882*0Sstevel@tonic-gate $found = 1; 883*0Sstevel@tonic-gate push @$pod, "=head1 Found in $file\n\n" unless $found_in{$file}++; 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate elsif (/^=head[12]/) { 886*0Sstevel@tonic-gate $found = 0; 887*0Sstevel@tonic-gate } 888*0Sstevel@tonic-gate next unless $found; 889*0Sstevel@tonic-gate push @$pod, $_; 890*0Sstevel@tonic-gate } 891*0Sstevel@tonic-gate close(INFAQ); 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate die("No documentation for perl FAQ keyword `$search_key' found\n") 894*0Sstevel@tonic-gate unless @$pod; 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate return; 897*0Sstevel@tonic-gate} 898*0Sstevel@tonic-gate 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate#.......................................................................... 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gatesub render_findings { 903*0Sstevel@tonic-gate # Return the filename to open 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate my($self, $found_things) = @_; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate my $formatter_class = $self->{'formatter_class'} 908*0Sstevel@tonic-gate || die "No formatter class set!?"; 909*0Sstevel@tonic-gate my $formatter = $formatter_class->can('new') 910*0Sstevel@tonic-gate ? $formatter_class->new 911*0Sstevel@tonic-gate : $formatter_class 912*0Sstevel@tonic-gate ; 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate if(! @$found_things) { 915*0Sstevel@tonic-gate die "Nothing found?!"; 916*0Sstevel@tonic-gate # should have been caught before here 917*0Sstevel@tonic-gate } elsif(@$found_things > 1) { 918*0Sstevel@tonic-gate warn join '', 919*0Sstevel@tonic-gate "Perldoc is only really meant for reading one document at a time.\n", 920*0Sstevel@tonic-gate "So these parameters are being ignored: ", 921*0Sstevel@tonic-gate join(' ', @$found_things[1 .. $#$found_things] ), 922*0Sstevel@tonic-gate "\n" 923*0Sstevel@tonic-gate } 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate my $file = $found_things->[0]; 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate DEBUG > 3 and printf "Formatter switches now: [%s]\n", 928*0Sstevel@tonic-gate join ' ', map "[@$_]", @{ $self->{'formatter_switches'} }; 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate # Set formatter options: 931*0Sstevel@tonic-gate if( ref $formatter ) { 932*0Sstevel@tonic-gate foreach my $f (@{ $self->{'formatter_switches'} || [] }) { 933*0Sstevel@tonic-gate my($switch, $value, $silent_fail) = @$f; 934*0Sstevel@tonic-gate if( $formatter->can($switch) ) { 935*0Sstevel@tonic-gate eval { $formatter->$switch( defined($value) ? $value : () ) }; 936*0Sstevel@tonic-gate warn "Got an error when setting $formatter_class\->$switch:\n$@\n" 937*0Sstevel@tonic-gate if $@; 938*0Sstevel@tonic-gate } else { 939*0Sstevel@tonic-gate if( $silent_fail or $switch =~ m/^__/s ) { 940*0Sstevel@tonic-gate DEBUG > 2 and print "Formatter $formatter_class doesn't support $switch\n"; 941*0Sstevel@tonic-gate } else { 942*0Sstevel@tonic-gate warn "$formatter_class doesn't recognize the $switch switch.\n"; 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate } 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate } 947*0Sstevel@tonic-gate 948*0Sstevel@tonic-gate $self->{'output_is_binary'} = 949*0Sstevel@tonic-gate $formatter->can('write_with_binmode') && $formatter->write_with_binmode; 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate my ($out_fh, $out) = $self->new_output_file( 952*0Sstevel@tonic-gate ( $formatter->can('output_extension') && $formatter->output_extension ) 953*0Sstevel@tonic-gate || undef, 954*0Sstevel@tonic-gate $self->useful_filename_bit, 955*0Sstevel@tonic-gate ); 956*0Sstevel@tonic-gate 957*0Sstevel@tonic-gate # Now, finally, do the formatting! 958*0Sstevel@tonic-gate { 959*0Sstevel@tonic-gate local $^W = $^W; 960*0Sstevel@tonic-gate if(DEBUG() or $self->opt_v) { 961*0Sstevel@tonic-gate # feh, let 'em see it 962*0Sstevel@tonic-gate } else { 963*0Sstevel@tonic-gate $^W = 0; 964*0Sstevel@tonic-gate # The average user just has no reason to be seeing 965*0Sstevel@tonic-gate # $^W-suppressable warnings from the formatting! 966*0Sstevel@tonic-gate } 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate eval { $formatter->parse_from_file( $file, $out_fh ) }; 969*0Sstevel@tonic-gate } 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate warn "Error while formatting with $formatter_class:\n $@\n" if $@; 972*0Sstevel@tonic-gate DEBUG > 2 and print "Back from formatting with $formatter_class\n"; 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate close $out_fh 975*0Sstevel@tonic-gate or warn "Can't close $out: $!\n(Did $formatter already close it?)"; 976*0Sstevel@tonic-gate sleep 0; sleep 0; sleep 0; 977*0Sstevel@tonic-gate # Give the system a few timeslices to meditate on the fact 978*0Sstevel@tonic-gate # that the output file does in fact exist and is closed. 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate $self->unlink_if_temp_file($file); 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate unless( -s $out ) { 983*0Sstevel@tonic-gate if( $formatter->can( 'if_zero_length' ) ) { 984*0Sstevel@tonic-gate # Basically this is just a hook for Pod::Simple::Checker; since 985*0Sstevel@tonic-gate # what other class could /happily/ format an input file with Pod 986*0Sstevel@tonic-gate # as a 0-length output file? 987*0Sstevel@tonic-gate $formatter->if_zero_length( $file, $out, $out_fh ); 988*0Sstevel@tonic-gate } else { 989*0Sstevel@tonic-gate warn "Got a 0-length file from $$found_things[0] via $formatter_class!?\n" 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate } 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate DEBUG and print "Finished writing to $out.\n"; 994*0Sstevel@tonic-gate return($out, $formatter) if wantarray; 995*0Sstevel@tonic-gate return $out; 996*0Sstevel@tonic-gate} 997*0Sstevel@tonic-gate 998*0Sstevel@tonic-gate#.......................................................................... 999*0Sstevel@tonic-gate 1000*0Sstevel@tonic-gatesub unlink_if_temp_file { 1001*0Sstevel@tonic-gate # Unlink the specified file IFF it's in the list of temp files. 1002*0Sstevel@tonic-gate # Really only used in the case of -f / -q things when we can 1003*0Sstevel@tonic-gate # throw away the dynamically generated source pod file once 1004*0Sstevel@tonic-gate # we've formatted it. 1005*0Sstevel@tonic-gate # 1006*0Sstevel@tonic-gate my($self, $file) = @_; 1007*0Sstevel@tonic-gate return unless defined $file and length $file; 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate my $temp_file_list = $self->{'temp_file_list'} || return; 1010*0Sstevel@tonic-gate if(grep $_ eq $file, @$temp_file_list) { 1011*0Sstevel@tonic-gate $self->aside("Unlinking $file\n"); 1012*0Sstevel@tonic-gate unlink($file) or warn "Odd, couldn't unlink $file: $!"; 1013*0Sstevel@tonic-gate } else { 1014*0Sstevel@tonic-gate DEBUG > 1 and print "$file isn't a temp file, so not unlinking.\n"; 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate return; 1017*0Sstevel@tonic-gate} 1018*0Sstevel@tonic-gate 1019*0Sstevel@tonic-gate#.......................................................................... 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gatesub MSWin_temp_cleanup { 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate # Nothing particularly MSWin-specific in here, but I don't know if any 1024*0Sstevel@tonic-gate # other OS needs its temp dir policed like MSWin does! 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate my $self = shift; 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate my $tempdir = $ENV{'TEMP'}; 1029*0Sstevel@tonic-gate return unless defined $tempdir and length $tempdir 1030*0Sstevel@tonic-gate and -e $tempdir and -d _ and -w _; 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate $self->aside( 1033*0Sstevel@tonic-gate "Considering whether any old files of mine in $tempdir need unlinking.\n" 1034*0Sstevel@tonic-gate ); 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate opendir(TMPDIR, $tempdir) || return; 1037*0Sstevel@tonic-gate my @to_unlink; 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate my $limit = time() - $Temp_File_Lifetime; 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate DEBUG > 5 and printf "Looking for things pre-dating %s (%x)\n", 1042*0Sstevel@tonic-gate ($limit) x 2; 1043*0Sstevel@tonic-gate 1044*0Sstevel@tonic-gate my $filespec; 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate while(defined($filespec = readdir(TMPDIR))) { 1047*0Sstevel@tonic-gate if( 1048*0Sstevel@tonic-gate $filespec =~ m{^perldoc_[a-zA-Z0-9]+_T([a-fA-F0-9]{7,})_[a-fA-F0-9]{3,}}s 1049*0Sstevel@tonic-gate ) { 1050*0Sstevel@tonic-gate if( hex($1) < $limit ) { 1051*0Sstevel@tonic-gate push @to_unlink, "$tempdir/$filespec"; 1052*0Sstevel@tonic-gate $self->aside( "Will unlink my old temp file $to_unlink[-1]\n" ); 1053*0Sstevel@tonic-gate } else { 1054*0Sstevel@tonic-gate DEBUG > 5 and 1055*0Sstevel@tonic-gate printf " $tempdir/$filespec is too recent (after %x)\n", $limit; 1056*0Sstevel@tonic-gate } 1057*0Sstevel@tonic-gate } else { 1058*0Sstevel@tonic-gate DEBUG > 5 and 1059*0Sstevel@tonic-gate print " $tempdir/$filespec doesn't look like a perldoc temp file.\n"; 1060*0Sstevel@tonic-gate } 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate closedir(TMPDIR); 1063*0Sstevel@tonic-gate $self->aside(sprintf "Unlinked %s items of mine in %s\n", 1064*0Sstevel@tonic-gate scalar(unlink(@to_unlink)), 1065*0Sstevel@tonic-gate $tempdir 1066*0Sstevel@tonic-gate ); 1067*0Sstevel@tonic-gate return; 1068*0Sstevel@tonic-gate} 1069*0Sstevel@tonic-gate 1070*0Sstevel@tonic-gate# . . . . . . . . . . . . . . . . . . . . . . . . . 1071*0Sstevel@tonic-gate 1072*0Sstevel@tonic-gatesub MSWin_perldoc_tempfile { 1073*0Sstevel@tonic-gate my($self, $suffix, $infix) = @_; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate my $tempdir = $ENV{'TEMP'}; 1076*0Sstevel@tonic-gate return unless defined $tempdir and length $tempdir 1077*0Sstevel@tonic-gate and -e $tempdir and -d _ and -w _; 1078*0Sstevel@tonic-gate 1079*0Sstevel@tonic-gate my $spec; 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate do { 1082*0Sstevel@tonic-gate $spec = sprintf "%s/perldoc_%s_T%x_%x%02x.%s", # used also in MSWin_temp_cleanup 1083*0Sstevel@tonic-gate # Yes, we embed the create-time in the filename! 1084*0Sstevel@tonic-gate $tempdir, 1085*0Sstevel@tonic-gate $infix || 'x', 1086*0Sstevel@tonic-gate time(), 1087*0Sstevel@tonic-gate $$, 1088*0Sstevel@tonic-gate defined( &Win32::GetTickCount ) 1089*0Sstevel@tonic-gate ? (Win32::GetTickCount() & 0xff) 1090*0Sstevel@tonic-gate : int(rand 256) 1091*0Sstevel@tonic-gate # Under MSWin, $$ values get reused quickly! So if we ran 1092*0Sstevel@tonic-gate # perldoc foo and then perldoc bar before there was time for 1093*0Sstevel@tonic-gate # time() to increment time."_$$" would likely be the same 1094*0Sstevel@tonic-gate # for each process! So we tack on the tick count's lower 1095*0Sstevel@tonic-gate # bits (or, in a pinch, rand) 1096*0Sstevel@tonic-gate , 1097*0Sstevel@tonic-gate $suffix || 'txt'; 1098*0Sstevel@tonic-gate ; 1099*0Sstevel@tonic-gate } while( -e $spec ); 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate my $counter = 0; 1102*0Sstevel@tonic-gate 1103*0Sstevel@tonic-gate while($counter < 50) { 1104*0Sstevel@tonic-gate my $fh; 1105*0Sstevel@tonic-gate # If we are running before perl5.6.0, we can't autovivify 1106*0Sstevel@tonic-gate if ($] < 5.006) { 1107*0Sstevel@tonic-gate require Symbol; 1108*0Sstevel@tonic-gate $fh = Symbol::gensym(); 1109*0Sstevel@tonic-gate } 1110*0Sstevel@tonic-gate DEBUG > 3 and print "About to try making temp file $spec\n"; 1111*0Sstevel@tonic-gate return($fh, $spec) if open($fh, ">", $spec); # XXX 5.6ism 1112*0Sstevel@tonic-gate $self->aside("Can't create temp file $spec: $!\n"); 1113*0Sstevel@tonic-gate } 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate $self->aside("Giving up on making a temp file!\n"); 1116*0Sstevel@tonic-gate die "Can't make a tempfile!?"; 1117*0Sstevel@tonic-gate} 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate#.......................................................................... 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gatesub after_rendering { 1123*0Sstevel@tonic-gate my $self = $_[0]; 1124*0Sstevel@tonic-gate $self->after_rendering_VMS if IS_VMS; 1125*0Sstevel@tonic-gate $self->after_rendering_MSWin32 if IS_MSWin32; 1126*0Sstevel@tonic-gate $self->after_rendering_Dos if IS_Dos; 1127*0Sstevel@tonic-gate $self->after_rendering_OS2 if IS_OS2; 1128*0Sstevel@tonic-gate return; 1129*0Sstevel@tonic-gate} 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gatesub after_rendering_VMS { return } 1132*0Sstevel@tonic-gatesub after_rendering_Dos { return } 1133*0Sstevel@tonic-gatesub after_rendering_OS2 { return } 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gatesub after_rendering_MSWin32 { 1136*0Sstevel@tonic-gate shift->MSWin_temp_cleanup() if $Temp_Files_Created; 1137*0Sstevel@tonic-gate} 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate#.......................................................................... 1140*0Sstevel@tonic-gate# : : : : : : : : : 1141*0Sstevel@tonic-gate#.......................................................................... 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gatesub minus_f_nocase { # i.e., do like -f, but without regard to case 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate my($self, $dir, $file) = @_; 1147*0Sstevel@tonic-gate my $path = catfile($dir,$file); 1148*0Sstevel@tonic-gate return $path if -f $path and -r _; 1149*0Sstevel@tonic-gate 1150*0Sstevel@tonic-gate if(!$self->opt_i 1151*0Sstevel@tonic-gate or IS_VMS or IS_MSWin32 1152*0Sstevel@tonic-gate or IS_Dos or IS_OS2 1153*0Sstevel@tonic-gate ) { 1154*0Sstevel@tonic-gate # On a case-forgiving file system, or if case is important, 1155*0Sstevel@tonic-gate # that is it, all we can do. 1156*0Sstevel@tonic-gate warn "Ignored $path: unreadable\n" if -f _; 1157*0Sstevel@tonic-gate return ''; 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate local *DIR; 1161*0Sstevel@tonic-gate my @p = ($dir); 1162*0Sstevel@tonic-gate my($p,$cip); 1163*0Sstevel@tonic-gate foreach $p (splitdir $file){ 1164*0Sstevel@tonic-gate my $try = catfile @p, $p; 1165*0Sstevel@tonic-gate $self->aside("Scrutinizing $try...\n"); 1166*0Sstevel@tonic-gate stat $try; 1167*0Sstevel@tonic-gate if (-d _) { 1168*0Sstevel@tonic-gate push @p, $p; 1169*0Sstevel@tonic-gate if ( $p eq $self->{'target'} ) { 1170*0Sstevel@tonic-gate my $tmp_path = catfile @p; 1171*0Sstevel@tonic-gate my $path_f = 0; 1172*0Sstevel@tonic-gate for (@{ $self->{'found'} }) { 1173*0Sstevel@tonic-gate $path_f = 1 if $_ eq $tmp_path; 1174*0Sstevel@tonic-gate } 1175*0Sstevel@tonic-gate push (@{ $self->{'found'} }, $tmp_path) unless $path_f; 1176*0Sstevel@tonic-gate $self->aside( "Found as $tmp_path but directory\n" ); 1177*0Sstevel@tonic-gate } 1178*0Sstevel@tonic-gate } 1179*0Sstevel@tonic-gate elsif (-f _ && -r _) { 1180*0Sstevel@tonic-gate return $try; 1181*0Sstevel@tonic-gate } 1182*0Sstevel@tonic-gate elsif (-f _) { 1183*0Sstevel@tonic-gate warn "Ignored $try: unreadable\n"; 1184*0Sstevel@tonic-gate } 1185*0Sstevel@tonic-gate elsif (-d catdir(@p)) { # at least we see the containing directory! 1186*0Sstevel@tonic-gate my $found = 0; 1187*0Sstevel@tonic-gate my $lcp = lc $p; 1188*0Sstevel@tonic-gate my $p_dirspec = catdir(@p); 1189*0Sstevel@tonic-gate opendir DIR, $p_dirspec or die "opendir $p_dirspec: $!"; 1190*0Sstevel@tonic-gate while(defined( $cip = readdir(DIR) )) { 1191*0Sstevel@tonic-gate if (lc $cip eq $lcp){ 1192*0Sstevel@tonic-gate $found++; 1193*0Sstevel@tonic-gate last; # XXX stop at the first? what if there's others? 1194*0Sstevel@tonic-gate } 1195*0Sstevel@tonic-gate } 1196*0Sstevel@tonic-gate closedir DIR or die "closedir $p_dirspec: $!"; 1197*0Sstevel@tonic-gate return "" unless $found; 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate push @p, $cip; 1200*0Sstevel@tonic-gate my $p_filespec = catfile(@p); 1201*0Sstevel@tonic-gate return $p_filespec if -f $p_filespec and -r _; 1202*0Sstevel@tonic-gate warn "Ignored $p_filespec: unreadable\n" if -f _; 1203*0Sstevel@tonic-gate } 1204*0Sstevel@tonic-gate } 1205*0Sstevel@tonic-gate return ""; 1206*0Sstevel@tonic-gate} 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate#.......................................................................... 1209*0Sstevel@tonic-gate 1210*0Sstevel@tonic-gatesub pagers_guessing { 1211*0Sstevel@tonic-gate my $self = shift; 1212*0Sstevel@tonic-gate 1213*0Sstevel@tonic-gate my @pagers; 1214*0Sstevel@tonic-gate push @pagers, $self->pagers; 1215*0Sstevel@tonic-gate $self->{'pagers'} = \@pagers; 1216*0Sstevel@tonic-gate 1217*0Sstevel@tonic-gate if (IS_MSWin32) { 1218*0Sstevel@tonic-gate push @pagers, qw( more< less notepad ); 1219*0Sstevel@tonic-gate unshift @pagers, $ENV{PAGER} if $ENV{PAGER}; 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate elsif (IS_VMS) { 1222*0Sstevel@tonic-gate push @pagers, qw( most more less type/page ); 1223*0Sstevel@tonic-gate } 1224*0Sstevel@tonic-gate elsif (IS_Dos) { 1225*0Sstevel@tonic-gate push @pagers, qw( less.exe more.com< ); 1226*0Sstevel@tonic-gate unshift @pagers, $ENV{PAGER} if $ENV{PAGER}; 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate else { 1229*0Sstevel@tonic-gate if (IS_OS2) { 1230*0Sstevel@tonic-gate unshift @pagers, 'less', 'cmd /c more <'; 1231*0Sstevel@tonic-gate } 1232*0Sstevel@tonic-gate push @pagers, qw( more less pg view cat ); 1233*0Sstevel@tonic-gate unshift @pagers, $ENV{PAGER} if $ENV{PAGER}; 1234*0Sstevel@tonic-gate } 1235*0Sstevel@tonic-gate unshift @pagers, $ENV{PERLDOC_PAGER} if $ENV{PERLDOC_PAGER}; 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate return; 1238*0Sstevel@tonic-gate} 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate#.......................................................................... 1241*0Sstevel@tonic-gate 1242*0Sstevel@tonic-gatesub page_module_file { 1243*0Sstevel@tonic-gate my($self, @found) = @_; 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate # Security note: 1246*0Sstevel@tonic-gate # Don't ever just pass this off to anything like MSWin's "start.exe", 1247*0Sstevel@tonic-gate # since we might be calling on a .pl file, and we wouldn't want that 1248*0Sstevel@tonic-gate # to actually /execute/ the file that we just want to page thru! 1249*0Sstevel@tonic-gate # Also a consideration if one were to use a web browser as a pager; 1250*0Sstevel@tonic-gate # doing so could trigger the browser's MIME mapping for whatever 1251*0Sstevel@tonic-gate # it thinks .pm/.pl/whatever is. Probably just a (useless and 1252*0Sstevel@tonic-gate # annoying) "Save as..." dialog, but potentially executing the file 1253*0Sstevel@tonic-gate # in question -- particularly in the case of MSIE and it's, ahem, 1254*0Sstevel@tonic-gate # occasionally hazy distinction between OS-local extension 1255*0Sstevel@tonic-gate # associations, and browser-specific MIME mappings. 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate if ($self->{'output_to_stdout'}) { 1258*0Sstevel@tonic-gate $self->aside("Sending unpaged output to STDOUT.\n"); 1259*0Sstevel@tonic-gate local $_; 1260*0Sstevel@tonic-gate my $any_error = 0; 1261*0Sstevel@tonic-gate foreach my $output (@found) { 1262*0Sstevel@tonic-gate unless( open(TMP, "<", $output) ) { # XXX 5.6ism 1263*0Sstevel@tonic-gate warn("Can't open $output: $!"); 1264*0Sstevel@tonic-gate $any_error = 1; 1265*0Sstevel@tonic-gate next; 1266*0Sstevel@tonic-gate } 1267*0Sstevel@tonic-gate while (<TMP>) { 1268*0Sstevel@tonic-gate print or die "Can't print to stdout: $!"; 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate close TMP or die "Can't close while $output: $!"; 1271*0Sstevel@tonic-gate $self->unlink_if_temp_file($output); 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate return $any_error; # successful 1274*0Sstevel@tonic-gate } 1275*0Sstevel@tonic-gate 1276*0Sstevel@tonic-gate foreach my $pager ( $self->pagers ) { 1277*0Sstevel@tonic-gate $self->aside("About to try calling $pager @found\n"); 1278*0Sstevel@tonic-gate if (system($pager, @found) == 0) { 1279*0Sstevel@tonic-gate $self->aside("Yay, it worked.\n"); 1280*0Sstevel@tonic-gate return 0; 1281*0Sstevel@tonic-gate } 1282*0Sstevel@tonic-gate $self->aside("That didn't work.\n"); 1283*0Sstevel@tonic-gate 1284*0Sstevel@tonic-gate # Odd -- when it fails, under Win32, this seems to neither 1285*0Sstevel@tonic-gate # return with a fail nor return with a success!! 1286*0Sstevel@tonic-gate # That's discouraging! 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate $self->aside( 1290*0Sstevel@tonic-gate sprintf "Can't manage to find a way to page [%s] via pagers [%s]\n", 1291*0Sstevel@tonic-gate join(' ', @found), 1292*0Sstevel@tonic-gate join(' ', $self->pagers), 1293*0Sstevel@tonic-gate ); 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate if (IS_VMS) { 1296*0Sstevel@tonic-gate DEBUG > 1 and print "Bailing out in a VMSish way.\n"; 1297*0Sstevel@tonic-gate eval q{ 1298*0Sstevel@tonic-gate use vmsish qw(status exit); 1299*0Sstevel@tonic-gate exit $?; 1300*0Sstevel@tonic-gate 1; 1301*0Sstevel@tonic-gate } or die; 1302*0Sstevel@tonic-gate } 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate return 1; 1305*0Sstevel@tonic-gate # i.e., an UNSUCCESSFUL return value! 1306*0Sstevel@tonic-gate} 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate#.......................................................................... 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gatesub check_file { 1311*0Sstevel@tonic-gate my($self, $dir, $file) = @_; 1312*0Sstevel@tonic-gate 1313*0Sstevel@tonic-gate unless( ref $self ) { 1314*0Sstevel@tonic-gate # Should never get called: 1315*0Sstevel@tonic-gate $Carp::Verbose = 1; 1316*0Sstevel@tonic-gate Carp::croak join '', 1317*0Sstevel@tonic-gate "Crazy ", __PACKAGE__, " error:\n", 1318*0Sstevel@tonic-gate "check_file must be an object_method!\n", 1319*0Sstevel@tonic-gate "Aborting" 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate if(length $dir and not -d $dir) { 1323*0Sstevel@tonic-gate DEBUG > 3 and print " No dir $dir -- skipping.\n"; 1324*0Sstevel@tonic-gate return ""; 1325*0Sstevel@tonic-gate } 1326*0Sstevel@tonic-gate 1327*0Sstevel@tonic-gate if ($self->opt_m) { 1328*0Sstevel@tonic-gate return $self->minus_f_nocase($dir,$file); 1329*0Sstevel@tonic-gate } 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate else { 1332*0Sstevel@tonic-gate my $path = $self->minus_f_nocase($dir,$file); 1333*0Sstevel@tonic-gate if( length $path and $self->containspod($path) ) { 1334*0Sstevel@tonic-gate DEBUG > 3 and print 1335*0Sstevel@tonic-gate " The file $path indeed looks promising!\n"; 1336*0Sstevel@tonic-gate return $path; 1337*0Sstevel@tonic-gate } 1338*0Sstevel@tonic-gate } 1339*0Sstevel@tonic-gate DEBUG > 3 and print " No good: $file in $dir\n"; 1340*0Sstevel@tonic-gate 1341*0Sstevel@tonic-gate return ""; 1342*0Sstevel@tonic-gate} 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate#.......................................................................... 1345*0Sstevel@tonic-gate 1346*0Sstevel@tonic-gatesub containspod { 1347*0Sstevel@tonic-gate my($self, $file, $readit) = @_; 1348*0Sstevel@tonic-gate return 1 if !$readit && $file =~ /\.pod\z/i; 1349*0Sstevel@tonic-gate 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate # Under cygwin the /usr/bin/perl is legal executable, but 1352*0Sstevel@tonic-gate # you cannot open a file with that name. It must be spelled 1353*0Sstevel@tonic-gate # out as "/usr/bin/perl.exe". 1354*0Sstevel@tonic-gate # 1355*0Sstevel@tonic-gate # The following if-case under cygwin prevents error 1356*0Sstevel@tonic-gate # 1357*0Sstevel@tonic-gate # $ perldoc perl 1358*0Sstevel@tonic-gate # Cannot open /usr/bin/perl: no such file or directory 1359*0Sstevel@tonic-gate # 1360*0Sstevel@tonic-gate # This would work though 1361*0Sstevel@tonic-gate # 1362*0Sstevel@tonic-gate # $ perldoc perl.pod 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate if ( IS_Cygwin and -x $file and -f "$file.exe" ) 1365*0Sstevel@tonic-gate { 1366*0Sstevel@tonic-gate warn "Cygwin $file.exe search skipped\n" if DEBUG or $self->opt_v; 1367*0Sstevel@tonic-gate return 0; 1368*0Sstevel@tonic-gate } 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate local($_); 1371*0Sstevel@tonic-gate open(TEST,"<", $file) or die "Can't open $file: $!"; # XXX 5.6ism 1372*0Sstevel@tonic-gate while (<TEST>) { 1373*0Sstevel@tonic-gate if (/^=head/) { 1374*0Sstevel@tonic-gate close(TEST) or die "Can't close $file: $!"; 1375*0Sstevel@tonic-gate return 1; 1376*0Sstevel@tonic-gate } 1377*0Sstevel@tonic-gate } 1378*0Sstevel@tonic-gate close(TEST) or die "Can't close $file: $!"; 1379*0Sstevel@tonic-gate return 0; 1380*0Sstevel@tonic-gate} 1381*0Sstevel@tonic-gate 1382*0Sstevel@tonic-gate#.......................................................................... 1383*0Sstevel@tonic-gate 1384*0Sstevel@tonic-gatesub maybe_diddle_INC { 1385*0Sstevel@tonic-gate my $self = shift; 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate # Does this look like a module or extension directory? 1388*0Sstevel@tonic-gate 1389*0Sstevel@tonic-gate if (-f "Makefile.PL") { 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate # Add "." and "lib" to @INC (if they exist) 1392*0Sstevel@tonic-gate eval q{ use lib qw(. lib); 1; } or die; 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate # don't add if superuser 1395*0Sstevel@tonic-gate if ($< && $> && -f "blib") { # don't be looking too hard now! 1396*0Sstevel@tonic-gate eval q{ use blib; 1 }; 1397*0Sstevel@tonic-gate warn $@ if $@ && $self->opt_v; 1398*0Sstevel@tonic-gate } 1399*0Sstevel@tonic-gate } 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate return; 1402*0Sstevel@tonic-gate} 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate#.......................................................................... 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gatesub new_output_file { 1407*0Sstevel@tonic-gate my $self = shift; 1408*0Sstevel@tonic-gate my $outspec = $self->opt_d; # Yes, -d overrides all else! 1409*0Sstevel@tonic-gate # So don't call this twice per format-job! 1410*0Sstevel@tonic-gate 1411*0Sstevel@tonic-gate return $self->new_tempfile(@_) unless defined $outspec and length $outspec; 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate # Otherwise open a write-handle on opt_d!f 1414*0Sstevel@tonic-gate 1415*0Sstevel@tonic-gate my $fh; 1416*0Sstevel@tonic-gate # If we are running before perl5.6.0, we can't autovivify 1417*0Sstevel@tonic-gate if ($] < 5.006) { 1418*0Sstevel@tonic-gate require Symbol; 1419*0Sstevel@tonic-gate $fh = Symbol::gensym(); 1420*0Sstevel@tonic-gate } 1421*0Sstevel@tonic-gate DEBUG > 3 and print "About to try writing to specified output file $outspec\n"; 1422*0Sstevel@tonic-gate die "Can't write-open $outspec: $!" 1423*0Sstevel@tonic-gate unless open($fh, ">", $outspec); # XXX 5.6ism 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate DEBUG > 3 and print "Successfully opened $outspec\n"; 1426*0Sstevel@tonic-gate binmode($fh) if $self->{'output_is_binary'}; 1427*0Sstevel@tonic-gate return($fh, $outspec); 1428*0Sstevel@tonic-gate} 1429*0Sstevel@tonic-gate 1430*0Sstevel@tonic-gate#.......................................................................... 1431*0Sstevel@tonic-gate 1432*0Sstevel@tonic-gatesub useful_filename_bit { 1433*0Sstevel@tonic-gate # This tries to provide a meaningful bit of text to do with the query, 1434*0Sstevel@tonic-gate # such as can be used in naming the file -- since if we're going to be 1435*0Sstevel@tonic-gate # opening windows on temp files (as a "pager" may well do!) then it's 1436*0Sstevel@tonic-gate # better if the temp file's name (which may well be used as the window 1437*0Sstevel@tonic-gate # title) isn't ALL just random garbage! 1438*0Sstevel@tonic-gate # In other words "perldoc_LWPSimple_2371981429" is a better temp file 1439*0Sstevel@tonic-gate # name than "perldoc_2371981429". So this routine is what tries to 1440*0Sstevel@tonic-gate # provide the "LWPSimple" bit. 1441*0Sstevel@tonic-gate # 1442*0Sstevel@tonic-gate my $self = shift; 1443*0Sstevel@tonic-gate my $pages = $self->{'pages'} || return undef; 1444*0Sstevel@tonic-gate return undef unless @$pages; 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate my $chunk = $pages->[0]; 1447*0Sstevel@tonic-gate return undef unless defined $chunk; 1448*0Sstevel@tonic-gate $chunk =~ s/:://g; 1449*0Sstevel@tonic-gate $chunk =~ s/\.\w+$//g; # strip any extension 1450*0Sstevel@tonic-gate if( $chunk =~ m/([^\#\\:\/\$]+)$/s ) { # get basename, if it's a file 1451*0Sstevel@tonic-gate $chunk = $1; 1452*0Sstevel@tonic-gate } else { 1453*0Sstevel@tonic-gate return undef; 1454*0Sstevel@tonic-gate } 1455*0Sstevel@tonic-gate $chunk =~ s/[^a-zA-Z0-9]+//g; # leave ONLY a-zA-Z0-9 things! 1456*0Sstevel@tonic-gate $chunk = substr($chunk, -10) if length($chunk) > 10; 1457*0Sstevel@tonic-gate return $chunk; 1458*0Sstevel@tonic-gate} 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate#.......................................................................... 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gatesub new_tempfile { # $self->new_tempfile( [$suffix, [$infix] ] ) 1463*0Sstevel@tonic-gate my $self = shift; 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate ++$Temp_Files_Created; 1466*0Sstevel@tonic-gate 1467*0Sstevel@tonic-gate if( IS_MSWin32 ) { 1468*0Sstevel@tonic-gate my @out = $self->MSWin_perldoc_tempfile(@_); 1469*0Sstevel@tonic-gate return @out if @out; 1470*0Sstevel@tonic-gate # otherwise fall thru to the normal stuff below... 1471*0Sstevel@tonic-gate } 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate require File::Temp; 1474*0Sstevel@tonic-gate return File::Temp::tempfile(UNLINK => 1); 1475*0Sstevel@tonic-gate} 1476*0Sstevel@tonic-gate 1477*0Sstevel@tonic-gate#.......................................................................... 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gatesub page { # apply a pager to the output file 1480*0Sstevel@tonic-gate my ($self, $output, $output_to_stdout, @pagers) = @_; 1481*0Sstevel@tonic-gate if ($output_to_stdout) { 1482*0Sstevel@tonic-gate $self->aside("Sending unpaged output to STDOUT.\n"); 1483*0Sstevel@tonic-gate open(TMP, "<", $output) or die "Can't open $output: $!"; # XXX 5.6ism 1484*0Sstevel@tonic-gate local $_; 1485*0Sstevel@tonic-gate while (<TMP>) { 1486*0Sstevel@tonic-gate print or die "Can't print to stdout: $!"; 1487*0Sstevel@tonic-gate } 1488*0Sstevel@tonic-gate close TMP or die "Can't close while $output: $!"; 1489*0Sstevel@tonic-gate $self->unlink_if_temp_file($output); 1490*0Sstevel@tonic-gate } else { 1491*0Sstevel@tonic-gate # On VMS, quoting prevents logical expansion, and temp files with no 1492*0Sstevel@tonic-gate # extension get the wrong default extension (such as .LIS for TYPE) 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate $output = VMS::Filespec::rmsexpand($output, '.') if IS_VMS; 1495*0Sstevel@tonic-gate foreach my $pager (@pagers) { 1496*0Sstevel@tonic-gate $self->aside("About to try calling $pager $output\n"); 1497*0Sstevel@tonic-gate if (IS_VMS) { 1498*0Sstevel@tonic-gate last if system("$pager $output") == 0; 1499*0Sstevel@tonic-gate } else { 1500*0Sstevel@tonic-gate last if system("$pager \"$output\"") == 0; 1501*0Sstevel@tonic-gate } 1502*0Sstevel@tonic-gate } 1503*0Sstevel@tonic-gate } 1504*0Sstevel@tonic-gate return; 1505*0Sstevel@tonic-gate} 1506*0Sstevel@tonic-gate 1507*0Sstevel@tonic-gate#.......................................................................... 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gatesub searchfor { 1510*0Sstevel@tonic-gate my($self, $recurse,$s,@dirs) = @_; 1511*0Sstevel@tonic-gate $s =~ s!::!/!g; 1512*0Sstevel@tonic-gate $s = VMS::Filespec::unixify($s) if IS_VMS; 1513*0Sstevel@tonic-gate return $s if -f $s && $self->containspod($s); 1514*0Sstevel@tonic-gate $self->aside( "Looking for $s in @dirs\n" ); 1515*0Sstevel@tonic-gate my $ret; 1516*0Sstevel@tonic-gate my $i; 1517*0Sstevel@tonic-gate my $dir; 1518*0Sstevel@tonic-gate $self->{'target'} = (splitdir $s)[-1]; # XXX: why not use File::Basename? 1519*0Sstevel@tonic-gate for ($i=0; $i<@dirs; $i++) { 1520*0Sstevel@tonic-gate $dir = $dirs[$i]; 1521*0Sstevel@tonic-gate ($dir = VMS::Filespec::unixpath($dir)) =~ s!/\z!! if IS_VMS; 1522*0Sstevel@tonic-gate if ( (! $self->opt_m && ( $ret = $self->check_file($dir,"$s.pod"))) 1523*0Sstevel@tonic-gate or ( $ret = $self->check_file($dir,"$s.pm")) 1524*0Sstevel@tonic-gate or ( $ret = $self->check_file($dir,$s)) 1525*0Sstevel@tonic-gate or ( IS_VMS and 1526*0Sstevel@tonic-gate $ret = $self->check_file($dir,"$s.com")) 1527*0Sstevel@tonic-gate or ( IS_OS2 and 1528*0Sstevel@tonic-gate $ret = $self->check_file($dir,"$s.cmd")) 1529*0Sstevel@tonic-gate or ( (IS_MSWin32 or IS_Dos or IS_OS2) and 1530*0Sstevel@tonic-gate $ret = $self->check_file($dir,"$s.bat")) 1531*0Sstevel@tonic-gate or ( $ret = $self->check_file("$dir/pod","$s.pod")) 1532*0Sstevel@tonic-gate or ( $ret = $self->check_file("$dir/pod",$s)) 1533*0Sstevel@tonic-gate or ( $ret = $self->check_file("$dir/pods","$s.pod")) 1534*0Sstevel@tonic-gate or ( $ret = $self->check_file("$dir/pods",$s)) 1535*0Sstevel@tonic-gate ) { 1536*0Sstevel@tonic-gate DEBUG > 1 and print " Found $ret\n"; 1537*0Sstevel@tonic-gate return $ret; 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate if ($recurse) { 1541*0Sstevel@tonic-gate opendir(D,$dir) or die "Can't opendir $dir: $!"; 1542*0Sstevel@tonic-gate my @newdirs = map catfile($dir, $_), grep { 1543*0Sstevel@tonic-gate not /^\.\.?\z/s and 1544*0Sstevel@tonic-gate not /^auto\z/s and # save time! don't search auto dirs 1545*0Sstevel@tonic-gate -d catfile($dir, $_) 1546*0Sstevel@tonic-gate } readdir D; 1547*0Sstevel@tonic-gate closedir(D) or die "Can't closedir $dir: $!"; 1548*0Sstevel@tonic-gate next unless @newdirs; 1549*0Sstevel@tonic-gate # what a wicked map! 1550*0Sstevel@tonic-gate @newdirs = map((s/\.dir\z//,$_)[1],@newdirs) if IS_VMS; 1551*0Sstevel@tonic-gate $self->aside( "Also looking in @newdirs\n" ); 1552*0Sstevel@tonic-gate push(@dirs,@newdirs); 1553*0Sstevel@tonic-gate } 1554*0Sstevel@tonic-gate } 1555*0Sstevel@tonic-gate return (); 1556*0Sstevel@tonic-gate} 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate#.......................................................................... 1559*0Sstevel@tonic-gate{ 1560*0Sstevel@tonic-gate my $already_asserted; 1561*0Sstevel@tonic-gate sub assert_closing_stdout { 1562*0Sstevel@tonic-gate my $self = shift; 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate return if $already_asserted; 1565*0Sstevel@tonic-gate 1566*0Sstevel@tonic-gate eval q~ END { close(STDOUT) || die "Can't close STDOUT: $!" } ~; 1567*0Sstevel@tonic-gate # What for? to let the pager know that nothing more will come? 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate die $@ if $@; 1570*0Sstevel@tonic-gate $already_asserted = 1; 1571*0Sstevel@tonic-gate return; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate} 1574*0Sstevel@tonic-gate 1575*0Sstevel@tonic-gate#.......................................................................... 1576*0Sstevel@tonic-gate 1577*0Sstevel@tonic-gatesub tweak_found_pathnames { 1578*0Sstevel@tonic-gate my($self, $found) = @_; 1579*0Sstevel@tonic-gate if (IS_MSWin32) { 1580*0Sstevel@tonic-gate foreach (@$found) { s,/,\\,g } 1581*0Sstevel@tonic-gate } 1582*0Sstevel@tonic-gate return; 1583*0Sstevel@tonic-gate} 1584*0Sstevel@tonic-gate 1585*0Sstevel@tonic-gate#.......................................................................... 1586*0Sstevel@tonic-gate# : : : : : : : : : 1587*0Sstevel@tonic-gate#.......................................................................... 1588*0Sstevel@tonic-gate 1589*0Sstevel@tonic-gatesub am_taint_checking { 1590*0Sstevel@tonic-gate my $self = shift; 1591*0Sstevel@tonic-gate die "NO ENVIRONMENT?!?!" unless keys %ENV; # reset iterator along the way 1592*0Sstevel@tonic-gate my($k,$v) = each %ENV; 1593*0Sstevel@tonic-gate return is_tainted($v); 1594*0Sstevel@tonic-gate} 1595*0Sstevel@tonic-gate 1596*0Sstevel@tonic-gate#.......................................................................... 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gatesub is_tainted { # just a function 1599*0Sstevel@tonic-gate my $arg = shift; 1600*0Sstevel@tonic-gate my $nada = substr($arg, 0, 0); # zero-length! 1601*0Sstevel@tonic-gate local $@; # preserve the caller's version of $@ 1602*0Sstevel@tonic-gate eval { eval "# $nada" }; 1603*0Sstevel@tonic-gate return length($@) != 0; 1604*0Sstevel@tonic-gate} 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate#.......................................................................... 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gatesub drop_privs_maybe { 1609*0Sstevel@tonic-gate my $self = shift; 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate # Attempt to drop privs if we should be tainting and aren't 1612*0Sstevel@tonic-gate if (!(IS_VMS || IS_MSWin32 || IS_Dos 1613*0Sstevel@tonic-gate || IS_OS2 1614*0Sstevel@tonic-gate ) 1615*0Sstevel@tonic-gate && ($> == 0 || $< == 0) 1616*0Sstevel@tonic-gate && !$self->am_taint_checking() 1617*0Sstevel@tonic-gate ) { 1618*0Sstevel@tonic-gate my $id = eval { getpwnam("nobody") }; 1619*0Sstevel@tonic-gate $id = eval { getpwnam("nouser") } unless defined $id; 1620*0Sstevel@tonic-gate $id = -2 unless defined $id; 1621*0Sstevel@tonic-gate # 1622*0Sstevel@tonic-gate # According to Stevens' APUE and various 1623*0Sstevel@tonic-gate # (BSD, Solaris, HP-UX) man pages, setting 1624*0Sstevel@tonic-gate # the real uid first and effective uid second 1625*0Sstevel@tonic-gate # is the way to go if one wants to drop privileges, 1626*0Sstevel@tonic-gate # because if one changes into an effective uid of 1627*0Sstevel@tonic-gate # non-zero, one cannot change the real uid any more. 1628*0Sstevel@tonic-gate # 1629*0Sstevel@tonic-gate # Actually, it gets even messier. There is 1630*0Sstevel@tonic-gate # a third uid, called the saved uid, and as 1631*0Sstevel@tonic-gate # long as that is zero, one can get back to 1632*0Sstevel@tonic-gate # uid of zero. Setting the real-effective *twice* 1633*0Sstevel@tonic-gate # helps in *most* systems (FreeBSD and Solaris) 1634*0Sstevel@tonic-gate # but apparently in HP-UX even this doesn't help: 1635*0Sstevel@tonic-gate # the saved uid stays zero (apparently the only way 1636*0Sstevel@tonic-gate # in HP-UX to change saved uid is to call setuid() 1637*0Sstevel@tonic-gate # when the effective uid is zero). 1638*0Sstevel@tonic-gate # 1639*0Sstevel@tonic-gate eval { 1640*0Sstevel@tonic-gate $< = $id; # real uid 1641*0Sstevel@tonic-gate $> = $id; # effective uid 1642*0Sstevel@tonic-gate $< = $id; # real uid 1643*0Sstevel@tonic-gate $> = $id; # effective uid 1644*0Sstevel@tonic-gate }; 1645*0Sstevel@tonic-gate if( !$@ && $< && $> ) { 1646*0Sstevel@tonic-gate DEBUG and print "OK, I dropped privileges.\n"; 1647*0Sstevel@tonic-gate } elsif( $self->opt_U ) { 1648*0Sstevel@tonic-gate DEBUG and print "Couldn't drop privileges, but in -U mode, so feh." 1649*0Sstevel@tonic-gate } else { 1650*0Sstevel@tonic-gate DEBUG and print "Hm, couldn't drop privileges. Ah well.\n"; 1651*0Sstevel@tonic-gate # We used to die here; but that seemed pointless. 1652*0Sstevel@tonic-gate } 1653*0Sstevel@tonic-gate } 1654*0Sstevel@tonic-gate return; 1655*0Sstevel@tonic-gate} 1656*0Sstevel@tonic-gate 1657*0Sstevel@tonic-gate#.......................................................................... 1658*0Sstevel@tonic-gate 1659*0Sstevel@tonic-gate1; 1660*0Sstevel@tonic-gate 1661*0Sstevel@tonic-gate__END__ 1662*0Sstevel@tonic-gate 1663*0Sstevel@tonic-gate# See "perldoc perldoc" for basic details. 1664*0Sstevel@tonic-gate# 1665*0Sstevel@tonic-gate# Perldoc -- look up a piece of documentation in .pod format that 1666*0Sstevel@tonic-gate# is embedded in the perl installation tree. 1667*0Sstevel@tonic-gate# 1668*0Sstevel@tonic-gate#~~~~~~ 1669*0Sstevel@tonic-gate# 1670*0Sstevel@tonic-gate# See ChangeLog in CPAN dist for Pod::Perldoc for later notes. 1671*0Sstevel@tonic-gate# 1672*0Sstevel@tonic-gate# Version 3.01: Sun Nov 10 21:38:09 MST 2002 1673*0Sstevel@tonic-gate# Sean M. Burke <sburke@cpan.org> 1674*0Sstevel@tonic-gate# Massive refactoring and code-tidying. 1675*0Sstevel@tonic-gate# Now it's a module(-family)! 1676*0Sstevel@tonic-gate# Formatter-specific stuff pulled out into Pod::Perldoc::To(Whatever).pm 1677*0Sstevel@tonic-gate# Added -T, -d, -o, -M, -w. 1678*0Sstevel@tonic-gate# Added some improved MSWin funk. 1679*0Sstevel@tonic-gate# 1680*0Sstevel@tonic-gate#~~~~~~ 1681*0Sstevel@tonic-gate# 1682*0Sstevel@tonic-gate# Version 2.05: Sat Oct 12 16:09:00 CEST 2002 1683*0Sstevel@tonic-gate# Hugo van der Sanden <hv@crypt.org> 1684*0Sstevel@tonic-gate# Made -U the default, based on patch from Simon Cozens 1685*0Sstevel@tonic-gate# Version 2.04: Sun Aug 18 13:27:12 BST 2002 1686*0Sstevel@tonic-gate# Randy W. Sims <RandyS@ThePierianSpring.org> 1687*0Sstevel@tonic-gate# allow -n to enable nroff under Win32 1688*0Sstevel@tonic-gate# Version 2.03: Sun Apr 23 16:56:34 BST 2000 1689*0Sstevel@tonic-gate# Hugo van der Sanden <hv@crypt.org> 1690*0Sstevel@tonic-gate# don't die when 'use blib' fails 1691*0Sstevel@tonic-gate# Version 2.02: Mon Mar 13 18:03:04 MST 2000 1692*0Sstevel@tonic-gate# Tom Christiansen <tchrist@perl.com> 1693*0Sstevel@tonic-gate# Added -U insecurity option 1694*0Sstevel@tonic-gate# Version 2.01: Sat Mar 11 15:22:33 MST 2000 1695*0Sstevel@tonic-gate# Tom Christiansen <tchrist@perl.com>, querulously. 1696*0Sstevel@tonic-gate# Security and correctness patches. 1697*0Sstevel@tonic-gate# What a twisted bit of distasteful spaghetti code. 1698*0Sstevel@tonic-gate# Version 2.0: ???? 1699*0Sstevel@tonic-gate# 1700*0Sstevel@tonic-gate#~~~~~~ 1701*0Sstevel@tonic-gate# 1702*0Sstevel@tonic-gate# Version 1.15: Tue Aug 24 01:50:20 EST 1999 1703*0Sstevel@tonic-gate# Charles Wilson <cwilson@ece.gatech.edu> 1704*0Sstevel@tonic-gate# changed /pod/ directory to /pods/ for cygwin 1705*0Sstevel@tonic-gate# to support cygwin/win32 1706*0Sstevel@tonic-gate# Version 1.14: Wed Jul 15 01:50:20 EST 1998 1707*0Sstevel@tonic-gate# Robin Barker <rmb1@cise.npl.co.uk> 1708*0Sstevel@tonic-gate# -strict, -w cleanups 1709*0Sstevel@tonic-gate# Version 1.13: Fri Feb 27 16:20:50 EST 1997 1710*0Sstevel@tonic-gate# Gurusamy Sarathy <gsar@activestate.com> 1711*0Sstevel@tonic-gate# -doc tweaks for -F and -X options 1712*0Sstevel@tonic-gate# Version 1.12: Sat Apr 12 22:41:09 EST 1997 1713*0Sstevel@tonic-gate# Gurusamy Sarathy <gsar@activestate.com> 1714*0Sstevel@tonic-gate# -various fixes for win32 1715*0Sstevel@tonic-gate# Version 1.11: Tue Dec 26 09:54:33 EST 1995 1716*0Sstevel@tonic-gate# Kenneth Albanowski <kjahds@kjahds.com> 1717*0Sstevel@tonic-gate# -added Charles Bailey's further VMS patches, and -u switch 1718*0Sstevel@tonic-gate# -added -t switch, with pod2text support 1719*0Sstevel@tonic-gate# 1720*0Sstevel@tonic-gate# Version 1.10: Thu Nov 9 07:23:47 EST 1995 1721*0Sstevel@tonic-gate# Kenneth Albanowski <kjahds@kjahds.com> 1722*0Sstevel@tonic-gate# -added VMS support 1723*0Sstevel@tonic-gate# -added better error recognition (on no found pages, just exit. On 1724*0Sstevel@tonic-gate# missing nroff/pod2man, just display raw pod.) 1725*0Sstevel@tonic-gate# -added recursive/case-insensitive matching (thanks, Andreas). This 1726*0Sstevel@tonic-gate# slows things down a bit, unfortunately. Give a precise name, and 1727*0Sstevel@tonic-gate# it'll run faster. 1728*0Sstevel@tonic-gate# 1729*0Sstevel@tonic-gate# Version 1.01: Tue May 30 14:47:34 EDT 1995 1730*0Sstevel@tonic-gate# Andy Dougherty <doughera@lafcol.lafayette.edu> 1731*0Sstevel@tonic-gate# -added pod documentation. 1732*0Sstevel@tonic-gate# -added PATH searching. 1733*0Sstevel@tonic-gate# -added searching pod/ subdirectory (mainly to pick up perlfunc.pod 1734*0Sstevel@tonic-gate# and friends. 1735*0Sstevel@tonic-gate# 1736*0Sstevel@tonic-gate#~~~~~~~ 1737*0Sstevel@tonic-gate# 1738*0Sstevel@tonic-gate# TODO: 1739*0Sstevel@tonic-gate# 1740*0Sstevel@tonic-gate# Cache the directories read during sloppy match 1741*0Sstevel@tonic-gate# (To disk, or just in-memory?) 1742*0Sstevel@tonic-gate# 1743*0Sstevel@tonic-gate# Backport this to perl 5.005? 1744*0Sstevel@tonic-gate# 1745*0Sstevel@tonic-gate# Implement at least part of the "perlman" interface described 1746*0Sstevel@tonic-gate# in Programming Perl 3e? 1747