File Coverage

blib/lib/Pod/Perldoc.pm
Criterion Covered Total %
statement 49 925 5.3
branch 18 632 2.8
condition 1 353 0.2
subroutine 15 88 17.0
pod 0 71 0.0
total 83 2069 4.0


line stmt bran cond sub pod time code
1 1     1   1464 use 5.006; # we use some open(X, "<", $y) syntax
  1         3  
2              
3             package Pod::Perldoc;
4 1     1   4 use strict;
  1         1  
  1         19  
5 1     1   23 use warnings;
  1         1  
  1         32  
6 1     1   2 use Config '%Config';
  1         1  
  1         35  
7              
8 1     1   3 use Fcntl; # for sysopen
  1         0  
  1         225  
9 1     1   7 use File::Basename qw(basename);
  1         1  
  1         56  
10 1     1   398 use File::Spec::Functions qw(catfile catdir splitdir);
  1         633  
  1         57  
11              
12 1         186 use vars qw($VERSION @Pagers $Bindir $Pod2man
13             $Temp_Files_Created $Temp_File_Lifetime
14 1     1   4 );
  1         1  
15             $VERSION = '3.27_02';
16              
17             #..........................................................................
18              
19             BEGIN { # Make a DEBUG constant very first thing...
20 1 50   1   4 unless(defined &DEBUG) {
21 1 50 50     12 if(($ENV{'PERLDOCDEBUG'} || '') =~ m/^(\d+)/) { # untaint
22 0         0 eval("sub DEBUG () {$1}");
23 0 0       0 die "WHAT? Couldn't eval-up a DEBUG constant!? $@" if $@;
24             } else {
25 1         15 *DEBUG = sub () {0};
26             }
27             }
28             }
29              
30 1     1   380 use Pod::Perldoc::GetOptsOO; # uses the DEBUG.
  1         1  
  1         24  
31 1     1   5 use Carp qw(croak carp);
  1         1  
  1         337  
32              
33             # these are also in BaseTo, which I don't want to inherit
34             sub debugging {
35 0     0 0   my $self = shift;
36              
37 0 0         ( defined(&Pod::Perldoc::DEBUG) and &Pod::Perldoc::DEBUG() )
38             }
39              
40             sub debug {
41 0     0 0   my( $self, @messages ) = @_;
42 0 0         return unless $self->debugging;
43 0           print STDERR map { "DEBUG : $_" } @messages;
  0            
44             }
45              
46             sub warn {
47 0     0 0   my( $self, @messages ) = @_;
48              
49 0           carp( join "\n", @messages, '' );
50             }
51              
52             sub die {
53 0     0 0   my( $self, @messages ) = @_;
54              
55 0           croak( join "\n", @messages, '' );
56             }
57              
58             #..........................................................................
59              
60             sub TRUE () {1}
61 0     0 0   sub FALSE () {return}
62             sub BE_LENIENT () {1}
63              
64             BEGIN {
65 1 50   1   7 *is_vms = $^O eq 'VMS' ? \&TRUE : \&FALSE unless defined &is_vms;
    50          
66 1 50       4 *is_mswin32 = $^O eq 'MSWin32' ? \&TRUE : \&FALSE unless defined &is_mswin32;
    50          
67 1 50       3 *is_dos = $^O eq 'dos' ? \&TRUE : \&FALSE unless defined &is_dos;
    50          
68 1 50       3 *is_os2 = $^O eq 'os2' ? \&TRUE : \&FALSE unless defined &is_os2;
    50          
69 1 50       5 *is_cygwin = $^O eq 'cygwin' ? \&TRUE : \&FALSE unless defined &is_cygwin;
    50          
70 1 50       4 *is_linux = $^O eq 'linux' ? \&TRUE : \&FALSE unless defined &is_linux;
    50          
71 1 50       4 *is_hpux = $^O =~ m/hpux/ ? \&TRUE : \&FALSE unless defined &is_hpux;
    50          
72 1 50       111 *is_amigaos = $^O eq 'amigaos' ? \&TRUE : \&FALSE unless defined &is_amigaos;
    50          
73             }
74              
75             $Temp_File_Lifetime ||= 60 * 60 * 24 * 5;
76             # If it's older than five days, it's quite unlikely
77             # that anyone's still looking at it!!
78             # (Currently used only by the MSWin cleanup routine)
79              
80              
81             #..........................................................................
82             { my $pager = $Config{'pager'};
83             push @Pagers, $pager if -x (split /\s+/, $pager)[0] or __PACKAGE__->is_vms;
84             }
85             $Bindir = $Config{'scriptdirexp'};
86             $Pod2man = "pod2man" . ( $Config{'versiononly'} ? $Config{'version'} : '' );
87              
88             # End of class-init stuff
89             #
90             ###########################################################################
91             #
92             # Option accessors...
93              
94             foreach my $subname (map "opt_$_", split '', q{mhlDriFfXqnTdULva}) {
95 1     1   4 no strict 'refs';
  1         1  
  1         23  
96 1     1   3 *$subname = do{ use strict 'refs'; sub () { shift->_elem($subname, @_) } };
  1     0   1  
  1         1345  
  0            
97             }
98              
99             # And these are so that GetOptsOO knows they take options:
100 0     0 0   sub opt_a_with { shift->_elem('opt_a', @_) }
101 0     0 0   sub opt_f_with { shift->_elem('opt_f', @_) }
102 0     0 0   sub opt_q_with { shift->_elem('opt_q', @_) }
103 0     0 0   sub opt_d_with { shift->_elem('opt_d', @_) }
104 0     0 0   sub opt_L_with { shift->_elem('opt_L', @_) }
105 0     0 0   sub opt_v_with { shift->_elem('opt_v', @_) }
106              
107             sub opt_w_with { # Specify an option for the formatter subclass
108 0     0 0   my($self, $value) = @_;
109 0 0         if($value =~ m/^([-_a-zA-Z][-_a-zA-Z0-9]*)(?:[=\:](.*?))?$/s) {
110 0           my $option = $1;
111 0 0         my $option_value = defined($2) ? $2 : "TRUE";
112 0           $option =~ tr/\-/_/s; # tolerate "foo-bar" for "foo_bar"
113 0           $self->add_formatter_option( $option, $option_value );
114             } else {
115 0           $self->warn( qq("$value" isn't a good formatter option name. I'm ignoring it!\n ) );
116             }
117 0           return;
118             }
119              
120             sub opt_M_with { # specify formatter class name(s)
121 0     0 0   my($self, $classes) = @_;
122 0 0 0       return unless defined $classes and length $classes;
123 0           DEBUG > 4 and print "Considering new formatter classes -M$classes\n";
124 0           my @classes_to_add;
125 0           foreach my $classname (split m/[,;]+/s, $classes) {
126 0 0         next unless $classname =~ m/\S/;
127 0 0         if( $classname =~ m/^(\w+(::\w+)+)$/s ) {
128             # A mildly restrictive concept of what modulenames are valid.
129 0           push @classes_to_add, $1; # untaint
130             } else {
131 0           $self->warn( qq("$classname" isn't a valid classname. Ignoring.\n) );
132             }
133             }
134              
135 0           unshift @{ $self->{'formatter_classes'} }, @classes_to_add;
  0            
136              
137 0           DEBUG > 3 and print(
138             "Adding @classes_to_add to the list of formatter classes, "
139             . "making them @{ $self->{'formatter_classes'} }.\n"
140             );
141              
142 0           return;
143             }
144              
145             sub opt_V { # report version and exit
146 0 0 0 0 0   print join '',
147             "Perldoc v$VERSION, under perl v$] for $^O",
148              
149             (defined(&Win32::BuildNumber) and defined &Win32::BuildNumber())
150             ? (" (win32 build ", &Win32::BuildNumber(), ")") : (),
151              
152             (chr(65) eq 'A') ? () : " (non-ASCII)",
153              
154             "\n",
155             ;
156 0           exit;
157             }
158              
159             sub opt_t { # choose plaintext as output format
160 0     0 0   my $self = shift;
161 0 0 0       $self->opt_o_with('text') if @_ and $_[0];
162 0           return $self->_elem('opt_t', @_);
163             }
164              
165             sub opt_u { # choose raw pod as output format
166 0     0 0   my $self = shift;
167 0 0 0       $self->opt_o_with('pod') if @_ and $_[0];
168 0           return $self->_elem('opt_u', @_);
169             }
170              
171             sub opt_n_with {
172             # choose man as the output format, and specify the proggy to run
173 0     0 0   my $self = shift;
174 0 0 0       $self->opt_o_with('man') if @_ and $_[0];
175 0           $self->_elem('opt_n', @_);
176             }
177              
178             sub opt_o_with { # "o" for output format
179 0     0 0   my($self, $rest) = @_;
180 0 0 0       return unless defined $rest and length $rest;
181 0 0         if($rest =~ m/^(\w+)$/s) {
182 0           $rest = $1; #untaint
183             } else {
184 0           $self->warn( qq("$rest" isn't a valid output format. Skipping.\n") );
185 0           return;
186             }
187              
188 0           $self->aside("Noting \"$rest\" as desired output format...\n");
189              
190             # Figure out what class(es) that could actually mean...
191              
192 0           my @classes;
193 0           foreach my $prefix ("Pod::Perldoc::To", "Pod::Simple::", "Pod::") {
194             # Messy but smart:
195 0           foreach my $stem (
196             $rest, # Yes, try it first with the given capitalization
197             "\L$rest", "\L\u$rest", "\U$rest" # And then try variations
198              
199             ) {
200 0           $self->aside("Considering $prefix$stem\n");
201 0           push @classes, $prefix . $stem;
202             }
203              
204             # Tidier, but misses too much:
205             #push @classes, $prefix . ucfirst(lc($rest));
206             }
207 0           $self->opt_M_with( join ";", @classes );
208 0           return;
209             }
210              
211             ###########################################################################
212             # % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
213              
214             sub run { # to be called by the "perldoc" executable
215 0     0 0   my $class = shift;
216 0           if(DEBUG > 3) {
217             print "Parameters to $class\->run:\n";
218             my @x = @_;
219             while(@x) {
220             $x[1] = '' unless defined $x[1];
221             $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY';
222             print " [$x[0]] => [$x[1]]\n";
223             splice @x,0,2;
224             }
225             print "\n";
226             }
227 0   0       return $class -> new(@_) -> process() || 0;
228             }
229              
230             # % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
231             ###########################################################################
232              
233             sub new { # yeah, nothing fancy
234 0     0 0   my $class = shift;
235 0   0       my $new = bless {@_}, (ref($class) || $class);
236 0           DEBUG > 1 and print "New $class object $new\n";
237 0           $new->init();
238 0           $new;
239             }
240              
241             #..........................................................................
242              
243             sub aside { # If we're in -D or DEBUG mode, say this.
244 0     0 0   my $self = shift;
245 0 0         if( DEBUG or $self->opt_D ) {
246             my $out = join( '',
247 0           DEBUG ? do {
248             my $callsub = (caller(1))[3];
249             my $package = quotemeta(__PACKAGE__ . '::');
250             $callsub =~ s/^$package/'/os;
251             # the o is justified, as $package really won't change.
252             $callsub . ": ";
253             } : '',
254             @_,
255             );
256 0           if(DEBUG) { print $out } else { print STDERR $out }
  0            
257             }
258 0           return;
259             }
260              
261             #..........................................................................
262              
263             sub usage {
264 0     0 0   my $self = shift;
265 0 0         $self->warn( "@_\n" ) if @_;
266              
267             # Erase evidence of previous errors (if any), so exit status is simple.
268 0           $! = 0;
269              
270 0           CORE::die( <
271             perldoc [options] PageName|ModuleName|ProgramName|URL...
272             perldoc [options] -f BuiltinFunction
273             perldoc [options] -q FAQRegex
274             perldoc [options] -v PerlVariable
275              
276             Options:
277             -h Display this help message
278             -V Report version
279             -r Recursive search (slow)
280             -i Ignore case
281             -t Display pod using pod2text instead of Pod::Man and groff
282             (-t is the default on win32 unless -n is specified)
283             -u Display unformatted pod text
284             -m Display module's file in its entirety
285             -n Specify replacement for groff
286             -l Display the module's file name
287             -U Don't attempt to drop privs for security
288             -F Arguments are file names, not modules (implies -U)
289             -D Verbosely describe what's going on
290             -T Send output to STDOUT without any pager
291             -d output_filename_to_send_to
292             -o output_format_name
293             -M FormatterModuleNameToUse
294             -w formatter_option:option_value
295             -L translation_code Choose doc translation (if any)
296             -X Use index if present (looks for pod.idx at $Config{archlib})
297             -q Search the text of questions (not answers) in perlfaq[1-9]
298             -f Search Perl built-in functions
299             -a Search Perl API
300             -v Search predefined Perl variables
301              
302             PageName|ModuleName|ProgramName|URL...
303             is the name of a piece of documentation that you want to look at. You
304             may either give a descriptive name of the page (as in the case of
305             `perlfunc') the name of a module, either like `Term::Info' or like
306             `Term/Info', or the name of a program, like `perldoc', or a URL
307             starting with http(s).
308              
309             BuiltinFunction
310             is the name of a perl function. Will extract documentation from
311             `perlfunc' or `perlop'.
312              
313             FAQRegex
314             is a regex. Will search perlfaq[1-9] for and extract any
315             questions that match.
316              
317             Any switches in the PERLDOC environment variable will be used before the
318             command line arguments. The optional pod index file contains a list of
319             filenames, one per line.
320             [Perldoc v$VERSION]
321             EOF
322              
323             }
324              
325             #..........................................................................
326              
327             sub program_name {
328 0     0 0   my( $self ) = @_;
329              
330 0 0         if( my $link = readlink( $0 ) ) {
331 0           $self->debug( "The value in $0 is a symbolic link to $link\n" );
332             }
333              
334 0           my $basename = basename( $0 );
335              
336 0           $self->debug( "\$0 is [$0]\nbasename is [$basename]\n" );
337             # possible name forms
338             # perldoc
339             # perldoc-v5.14
340             # perldoc-5.14
341             # perldoc-5.14.2
342             # perlvar # an alias mentioned in Camel 3
343             {
344 0           my( $untainted ) = $basename =~ m/(
  0            
345             \A
346             perl
347             (?: doc | func | faq | help | op | toc | var # Camel 3
348             )
349             (?: -? v? \d+ \. \d+ (?:\. \d+)? )? # possible version
350             (?: \. (?: bat | exe | com ) )? # possible extension
351             \z
352             )
353             /x;
354              
355 0           $self->debug($untainted);
356 0 0         return $untainted if $untainted;
357             }
358              
359 0           $self->warn(<<"HERE");
360             You called the perldoc command with a name that I didn't recognize.
361             This might mean that someone is tricking you into running a
362             program you don't intend to use, but it also might mean that you
363             created your own link to perldoc. I think your program name is
364             [$basename].
365              
366             I'll allow this if the filename only has [a-zA-Z0-9._-].
367             HERE
368              
369             {
370 0           my( $untainted ) = $basename =~ m/(
  0            
371             \A [a-zA-Z0-9._-]+ \z
372             )/x;
373              
374 0           $self->debug($untainted);
375 0 0         return $untainted if $untainted;
376             }
377              
378 0           $self->die(<<"HERE");
379             I think that your name for perldoc is potentially unsafe, so I'm
380             going to disallow it. I'd rather you be safe than sorry. If you
381             intended to use the name I'm disallowing, please tell the maintainers
382             about it. Write to:
383              
384             Pod-Perldoc\@rt.cpan.org
385              
386             HERE
387             }
388              
389             #..........................................................................
390              
391             sub usage_brief {
392 0     0 0   my $self = shift;
393 0           my $program_name = $self->program_name;
394              
395 0           CORE::die( <<"EOUSAGE" );
396             Usage: $program_name [-hVriDtumUFXlT] [-n nroffer_program]
397             [-d output_filename] [-o output_format] [-M FormatterModule]
398             [-w formatter_option:option_value] [-L translation_code]
399             PageName|ModuleName|ProgramName
400              
401             Examples:
402              
403             $program_name -f PerlFunc
404             $program_name -q FAQKeywords
405             $program_name -v PerlVar
406             $program_name -a PerlAPI
407              
408             The -h option prints more help. Also try "$program_name perldoc" to get
409             acquainted with the system. [Perldoc v$VERSION]
410             EOUSAGE
411              
412             }
413              
414             #..........................................................................
415              
416 0     0 0   sub pagers { @{ shift->{'pagers'} } }
  0            
417              
418             #..........................................................................
419              
420             sub _elem { # handy scalar meta-accessor: shift->_elem("foo", @_)
421 0 0   0     if(@_ > 2) { return $_[0]{ $_[1] } = $_[2] }
  0            
422 0           else { return $_[0]{ $_[1] } }
423             }
424             #..........................................................................
425             ###########################################################################
426             #
427             # Init formatter switches, and start it off with __bindir and all that
428             # other stuff that ToMan.pm needs.
429             #
430              
431             sub init {
432 0     0 0   my $self = shift;
433              
434             # Make sure creat()s are neither too much nor too little
435 0           eval { umask(0077) }; # doubtless someone has no mask
  0            
436              
437 0 0         if ( $] < 5.008 ) {
438 0           $self->aside("Your old perl doesn't have proper unicode support.");
439             }
440             else {
441             # http://www.perl.com/pub/2012/04/perlunicookbook-decode-argv-as-utf8.html
442             # Decode command line arguments as UTF-8. See RT#98906 for example problem.
443 1     1   553 use Encode qw(decode_utf8);
  1         6730  
  1         7805  
444 0           @ARGV = map { decode_utf8($_, 1) } @ARGV;
  0            
445             }
446              
447 0   0       $self->{'args'} ||= \@ARGV;
448 0   0       $self->{'found'} ||= [];
449 0   0       $self->{'temp_file_list'} ||= [];
450              
451              
452 0           $self->{'target'} = undef;
453              
454 0           $self->init_formatter_class_list;
455              
456 0 0         $self->{'pagers' } = [@Pagers] unless exists $self->{'pagers'};
457 0 0         $self->{'bindir' } = $Bindir unless exists $self->{'bindir'};
458 0 0         $self->{'pod2man'} = $Pod2man unless exists $self->{'pod2man'};
459 0 0         $self->{'search_path'} = [ ] unless exists $self->{'search_path'};
460              
461 0           push @{ $self->{'formatter_switches'} = [] }, (
462             # Yeah, we could use a hashref, but maybe there's some class where options
463             # have to be ordered; so we'll use an arrayref.
464              
465             [ '__bindir' => $self->{'bindir' } ],
466 0           [ '__pod2man' => $self->{'pod2man'} ],
467             );
468              
469             DEBUG > 3 and printf "Formatter switches now: [%s]\n",
470 0           join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
471              
472 0           $self->{'translators'} = [];
473 0           $self->{'extra_search_dirs'} = [];
474              
475 0           return;
476             }
477              
478             #..........................................................................
479              
480             sub init_formatter_class_list {
481 0     0 0   my $self = shift;
482 0   0       $self->{'formatter_classes'} ||= [];
483              
484             # Remember, no switches have been read yet, when
485             # we've started this routine.
486              
487 0           $self->opt_M_with('Pod::Perldoc::ToPod'); # the always-there fallthru
488 0           $self->opt_o_with('text');
489             $self->opt_o_with('term')
490             unless $self->is_mswin32 || $self->is_dos || $self->is_amigaos
491             || !($ENV{TERM} && (
492 0 0 0       ($ENV{TERM} || '') !~ /dumb|emacs|none|unknown/i
      0        
      0        
      0        
493             ));
494              
495 0           return;
496             }
497              
498             #..........................................................................
499              
500             sub process {
501             # if this ever returns, its retval will be used for exit(RETVAL)
502              
503 0     0 0   my $self = shift;
504 0           DEBUG > 1 and print " Beginning process.\n";
505 0           DEBUG > 1 and print " Args: @{$self->{'args'}}\n\n";
506 0           if(DEBUG > 3) {
507             print "Object contents:\n";
508             my @x = %$self;
509             while(@x) {
510             $x[1] = '' unless defined $x[1];
511             $x[1] = "@{$x[1]}" if ref( $x[1] ) eq 'ARRAY';
512             print " [$x[0]] => [$x[1]]\n";
513             splice @x,0,2;
514             }
515             print "\n";
516             }
517              
518             # TODO: make it deal with being invoked as various different things
519             # such as perlfaq".
520              
521 0 0         return $self->usage_brief unless @{ $self->{'args'} };
  0            
522 0           $self->options_reading;
523 0           $self->pagers_guessing;
524 0           $self->aside(sprintf "$0 => %s v%s\n", ref($self), $self->VERSION);
525 0 0 0       $self->drop_privs_maybe unless ($self->opt_U || $self->opt_F);
526 0           $self->options_processing;
527              
528             # Hm, we have @pages and @found, but we only really act on one
529             # file per call, with the exception of the opt_q hack, and with
530             # -l things
531              
532 0           $self->aside("\n");
533              
534 0           my @pages;
535 0           $self->{'pages'} = \@pages;
536 0 0         if( $self->opt_f) { @pages = qw(perlfunc perlop) }
  0 0          
    0          
    0          
537 0           elsif( $self->opt_q) { @pages = ("perlfaq1" .. "perlfaq9") }
538 0           elsif( $self->opt_v) { @pages = ("perlvar") }
539 0           elsif( $self->opt_a) { @pages = ("perlapi") }
540 0           else { @pages = @{$self->{'args'}};
  0            
541             # @pages = __FILE__
542             # if @pages == 1 and $pages[0] eq 'perldoc';
543             }
544              
545 0 0         return $self->usage_brief unless @pages;
546              
547 0           $self->find_good_formatter_class();
548 0           $self->formatter_sanity_check();
549              
550 0           $self->maybe_extend_searchpath();
551             # for when we're apparently in a module or extension directory
552              
553 0           my @found = $self->grand_search_init(\@pages);
554 0 0         exit ($self->is_vms ? 98962 : 1) unless @found;
    0          
555              
556 0 0 0       if ($self->opt_l and not $self->opt_q ) {
557 0           DEBUG and print "We're in -l mode, so byebye after this:\n";
558 0           print join("\n", @found), "\n";
559 0           return;
560             }
561              
562 0           $self->tweak_found_pathnames(\@found);
563 0           $self->assert_closing_stdout;
564 0 0         return $self->page_module_file(@found) if $self->opt_m;
565 0           DEBUG > 2 and print "Found: [@found]\n";
566              
567 0           return $self->render_and_page(\@found);
568             }
569              
570             #..........................................................................
571             {
572              
573             my( %class_seen, %class_loaded );
574             sub find_good_formatter_class {
575 0     0 0   my $self = $_[0];
576 0 0         my @class_list = @{ $self->{'formatter_classes'} || [] };
  0            
577 0 0         $self->die( "WHAT? Nothing in the formatter class list!?" ) unless @class_list;
578              
579 0           local @INC = @INC;
580 0 0         pop @INC if $INC[-1] eq '.';
581              
582 0           my $good_class_found;
583 0           foreach my $c (@class_list) {
584 0           DEBUG > 4 and print "Trying to load $c...\n";
585 0 0         if($class_loaded{$c}) {
586 0           DEBUG > 4 and print "OK, the already-loaded $c it is!\n";
587 0           $good_class_found = $c;
588 0           last;
589             }
590              
591 0 0         if($class_seen{$c}) {
592 0           DEBUG > 4 and print
593             "I've tried $c before, and it's no good. Skipping.\n";
594 0           next;
595             }
596              
597 0           $class_seen{$c} = 1;
598              
599 0 0 0       if( $c->can('parse_from_file') ) {
    0 0        
600 0           DEBUG > 4 and print
601             "Interesting, the formatter class $c is already loaded!\n";
602              
603             } elsif(
604             ( $self->is_os2 or $self->is_mswin32 or $self->is_dos or $self->is_os2)
605             # the always case-insensitive filesystems
606             and $class_seen{lc("~$c")}++
607             ) {
608 0           DEBUG > 4 and print
609             "We already used something quite like \"\L$c\E\", so no point using $c\n";
610             # This avoids redefining the package.
611             } else {
612 0           DEBUG > 4 and print "Trying to eval 'require $c'...\n";
613              
614 0           local $^W = $^W;
615 0 0         if(DEBUG() or $self->opt_D) {
616             # feh, let 'em see it
617             } else {
618 0           $^W = 0;
619             # The average user just has no reason to be seeing
620             # $^W-suppressible warnings from the require!
621             }
622              
623 0           eval "require $c";
624 0 0         if($@) {
625 0           DEBUG > 4 and print "Couldn't load $c: $!\n";
626 0           next;
627             }
628             }
629              
630 0 0         if( $c->can('parse_from_file') ) {
631 0           DEBUG > 4 and print "Settling on $c\n";
632 0           my $v = $c->VERSION;
633 0 0 0       $v = ( defined $v and length $v ) ? " version $v" : '';
634 0           $self->aside("Formatter class $c$v successfully loaded!\n");
635 0           $good_class_found = $c;
636 0           last;
637             } else {
638 0           DEBUG > 4 and print "Class $c isn't a formatter?! Skipping.\n";
639             }
640             }
641              
642 0 0         $self->die( "Can't find any loadable formatter class in @class_list?!\nAborting" )
643             unless $good_class_found;
644              
645 0           $self->{'formatter_class'} = $good_class_found;
646 0           $self->aside("Will format with the class $good_class_found\n");
647              
648 0           return;
649             }
650              
651             }
652             #..........................................................................
653              
654             sub formatter_sanity_check {
655 0     0 0   my $self = shift;
656 0   0       my $formatter_class = $self->{'formatter_class'}
657             || $self->die( "NO FORMATTER CLASS YET!?" );
658              
659 0 0 0       if(!$self->opt_T # so -T can FORCE sending to STDOUT
      0        
      0        
660             and $formatter_class->can('is_pageable')
661             and !$formatter_class->is_pageable
662             and !$formatter_class->can('page_for_perldoc')
663             ) {
664 0   0       my $ext =
665             ($formatter_class->can('output_extension')
666             && $formatter_class->output_extension
667             ) || '';
668 0 0         $ext = ".$ext" if length $ext;
669              
670 0           my $me = $self->program_name;
671 0           $self->die(
672             "When using Perldoc to format with $formatter_class, you have to\n"
673             . "specify -T or -dsomefile$ext\n"
674             . "See `$me perldoc' for more information on those switches.\n" )
675             ;
676             }
677             }
678              
679             #..........................................................................
680              
681             sub render_and_page {
682 0     0 0   my($self, $found_list) = @_;
683              
684 0           $self->maybe_generate_dynamic_pod($found_list);
685              
686 0           my($out, $formatter) = $self->render_findings($found_list);
687              
688 0 0 0       if($self->opt_d) {
    0          
689             printf "Perldoc (%s) output saved to %s\n",
690 0   0       $self->{'formatter_class'} || ref($self),
691             $out;
692 0 0         print "But notice that it's 0 bytes long!\n" unless -s $out;
693              
694              
695             } elsif( # Allow the formatter to "page" itself, if it wants.
696             $formatter->can('page_for_perldoc')
697             and do {
698 0           $self->aside("Going to call $formatter\->page_for_perldoc(\"$out\")\n");
699 0 0         if( $formatter->page_for_perldoc($out, $self) ) {
700 0           $self->aside("page_for_perldoc returned true, so NOT paging with $self.\n");
701 0           1;
702             } else {
703 0           $self->aside("page_for_perldoc returned false, so paging with $self instead.\n");
704 0           '';
705             }
706             }
707             ) {
708             # Do nothing, since the formatter has "paged" it for itself.
709              
710             } else {
711             # Page it normally (internally)
712              
713 0 0         if( -s $out ) { # Usual case:
714 0           $self->page($out, $self->{'output_to_stdout'}, $self->pagers);
715              
716             } else {
717             # Odd case:
718 0           $self->aside("Skipping $out (from $$found_list[0] "
719             . "via $$self{'formatter_class'}) as it is 0-length.\n");
720              
721 0           push @{ $self->{'temp_file_list'} }, $out;
  0            
722 0           $self->unlink_if_temp_file($out);
723             }
724             }
725              
726 0           $self->after_rendering(); # any extra cleanup or whatever
727              
728 0           return;
729             }
730              
731             #..........................................................................
732              
733             sub options_reading {
734 0     0 0   my $self = shift;
735              
736 0 0 0       if( defined $ENV{"PERLDOC"} and length $ENV{"PERLDOC"} ) {
737 0           require Text::ParseWords;
738 0           $self->aside("Noting env PERLDOC setting of $ENV{'PERLDOC'}\n");
739             # Yes, appends to the beginning
740 0           unshift @{ $self->{'args'} },
741 0           Text::ParseWords::shellwords( $ENV{"PERLDOC"} )
742             ;
743 0           DEBUG > 1 and print " Args now: @{$self->{'args'}}\n\n";
744             } else {
745 0           DEBUG > 1 and print " Okay, no PERLDOC setting in ENV.\n";
746             }
747              
748 0           DEBUG > 1
749             and print " Args right before switch processing: @{$self->{'args'}}\n";
750              
751 0 0         Pod::Perldoc::GetOptsOO::getopts( $self, $self->{'args'}, 'YES' )
752             or return $self->usage;
753              
754 0           DEBUG > 1
755             and print " Args after switch processing: @{$self->{'args'}}\n";
756              
757 0 0         return $self->usage if $self->opt_h;
758              
759 0           return;
760             }
761              
762             #..........................................................................
763              
764             sub options_processing {
765 0     0 0   my $self = shift;
766              
767 0 0         if ($self->opt_X) {
768 0           my $podidx = "$Config{'archlib'}/pod.idx";
769 0 0 0       $podidx = "" unless -f $podidx && -r _ && -M _ <= 7;
      0        
770 0           $self->{'podidx'} = $podidx;
771             }
772              
773 0 0 0       $self->{'output_to_stdout'} = 1 if $self->opt_T or ! -t STDOUT;
774              
775 0           $self->options_sanity;
776              
777             # This used to set a default, but that's now moved into any
778             # formatter that cares to have a default.
779 0 0         if( $self->opt_n ) {
780 0           $self->add_formatter_option( '__nroffer' => $self->opt_n );
781             }
782              
783             # Get language from PERLDOC_POD2 environment variable
784 0 0 0       if ( ! $self->opt_L && $ENV{PERLDOC_POD2} ) {
785 0 0         if ( $ENV{PERLDOC_POD2} eq '1' ) {
786 0   0       $self->_elem('opt_L',(split(/\_/, $ENV{LC_ALL} || $ENV{LC_LANG} || $ENV{LANG}))[0] );
787             }
788             else {
789 0           $self->_elem('opt_L', $ENV{PERLDOC_POD2});
790             }
791             };
792              
793             # Adjust for using translation packages
794 0 0         $self->add_translator(split(/\s+/,$self->opt_L)) if $self->opt_L;
795              
796 0           return;
797             }
798              
799             #..........................................................................
800              
801             sub options_sanity {
802 0     0 0   my $self = shift;
803              
804             # The opts-counting stuff interacts quite badly with
805             # the $ENV{"PERLDOC"} stuff. I.e., if I have $ENV{"PERLDOC"}
806             # set to -t, and I specify -u on the command line, I don't want
807             # to be hectored at that -u and -t don't make sense together.
808              
809             #my $opts = grep $_ && 1, # yes, the count of the set ones
810             # $self->opt_t, $self->opt_u, $self->opt_m, $self->opt_l
811             #;
812             #
813             #$self->usage("only one of -t, -u, -m or -l") if $opts > 1;
814              
815              
816             # Any sanity-checking need doing here?
817              
818             # But does not make sense to set either -f or -q in $ENV{"PERLDOC"}
819 0 0 0       if( $self->opt_f or $self->opt_q or $self->opt_a) {
      0        
820 0           my $count;
821 0 0         $count++ if $self->opt_f;
822 0 0         $count++ if $self->opt_q;
823 0 0         $count++ if $self->opt_a;
824 0 0         $self->usage("Only one of -f or -q or -a") if $count > 1;
825             $self->warn(
826             "Perldoc is meant for reading one file at a time.\n",
827             "So these parameters are being ignored: ",
828 0           join(' ', @{$self->{'args'}}),
829             "\n" )
830 0 0         if @{$self->{'args'}}
  0            
831             }
832 0           return;
833             }
834              
835             #..........................................................................
836              
837             sub grand_search_init {
838 0     0 0   my($self, $pages, @found) = @_;
839              
840 0           foreach (@$pages) {
841 0 0         if (/^http(s)?:\/\//) {
842 0           require HTTP::Tiny;
843 0           require File::Temp;
844 0           my $response = HTTP::Tiny->new->get($_);
845 0 0         if ($response->{success}) {
846 0           my ($fh, $filename) = File::Temp::tempfile(UNLINK => 1);
847 0           $fh->print($response->{content});
848 0           push @found, $filename;
849 0 0         ($self->{podnames}{$filename} =
850             m{.*/([^/#?]+)} ? uc $1 : "UNKNOWN")
851             =~ s/\.P(?:[ML]|OD)\z//;
852             }
853             else {
854 0 0         print STDERR "No " .
855             ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n";
856             }
857 0           next;
858             }
859 0 0 0       if ($self->{'podidx'} && open(PODIDX, $self->{'podidx'})) {
860 0           my $searchfor = catfile split '::', $_;
861 0           $self->aside( "Searching for '$searchfor' in $self->{'podidx'}\n" );
862 0           local $_;
863 0           while () {
864 0           chomp;
865 0 0         push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?\z,i;
866             }
867 0 0         close(PODIDX) or $self->die( "Can't close $$self{'podidx'}: $!" );
868 0           next;
869             }
870              
871 0           $self->aside( "Searching for $_\n" );
872              
873 0 0         if ($self->opt_F) {
874 0 0         next unless -r;
875 0 0 0       push @found, $_ if $self->opt_l or $self->opt_m or $self->containspod($_);
      0        
876 0           next;
877             }
878              
879 0           my @searchdirs;
880              
881             # prepend extra search directories (including language specific)
882 0           push @searchdirs, @{ $self->{'extra_search_dirs'} };
  0            
883              
884             # We must look both in @INC for library modules and in $bindir
885             # for executables, like h2xs or perldoc itself.
886 0           push @searchdirs, ($self->{'bindir'}, @{$self->{search_path}}, @INC);
  0            
887 0 0         unless ($self->opt_m) {
888 0 0         if ($self->is_vms) {
889 0           my($i,$trn);
890 0           for ($i = 0; $trn = $ENV{'DCL$PATH;'.$i}; $i++) {
891 0           push(@searchdirs,$trn);
892             }
893 0           push(@searchdirs,'perl_root:[lib.pods]') # installed pods
894             }
895             else {
896             push(@searchdirs, grep(-d, split($Config{path_sep},
897 0           $ENV{'PATH'})));
898             }
899             }
900 0           my @files = $self->searchfor(0,$_,@searchdirs);
901 0 0 0       if (@files) {
    0          
902 0           $self->aside( "Found as @files\n" );
903             }
904             # add "perl" prefix, so "perldoc foo" may find perlfoo.pod
905             elsif (BE_LENIENT and !/\W/ and @files = $self->searchfor(0, "perl$_", @searchdirs)) {
906 0           $self->aside( "Loosely found as @files\n" );
907             }
908             else {
909             # no match, try recursive search
910 0           @searchdirs = grep(!/^\.\z/s,@INC);
911 0 0         @files= $self->searchfor(1,$_,@searchdirs) if $self->opt_r;
912 0 0         if (@files) {
913 0           $self->aside( "Loosely found as @files\n" );
914             }
915             else {
916 0 0         print STDERR "No " .
917             ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n";
918 0 0         if ( @{ $self->{'found'} } ) {
  0            
919 0           print STDERR "However, try\n";
920 0           my $me = $self->program_name;
921 0           for my $dir (@{ $self->{'found'} }) {
  0            
922 0 0         opendir(DIR, $dir) or $self->die( "opendir $dir: $!" );
923 0           while (my $file = readdir(DIR)) {
924 0 0         next if ($file =~ /^\./s);
925 0           $file =~ s/\.(pm|pod)\z//; # XXX: badfs
926 0           print STDERR "\t$me $_\::$file\n";
927             }
928 0 0         closedir(DIR) or $self->die( "closedir $dir: $!" );
929             }
930             }
931             }
932             }
933 0           push(@found,@files);
934             }
935 0           return @found;
936             }
937              
938             #..........................................................................
939              
940             sub maybe_generate_dynamic_pod {
941 0     0 0   my($self, $found_things) = @_;
942 0           my @dynamic_pod;
943              
944 0 0         $self->search_perlapi($found_things, \@dynamic_pod) if $self->opt_a;
945              
946 0 0         $self->search_perlfunc($found_things, \@dynamic_pod) if $self->opt_f;
947              
948 0 0         $self->search_perlvar($found_things, \@dynamic_pod) if $self->opt_v;
949              
950 0 0         $self->search_perlfaqs($found_things, \@dynamic_pod) if $self->opt_q;
951              
952 0 0 0       if( ! $self->opt_f and ! $self->opt_q and ! $self->opt_v and ! $self->opt_a) {
    0          
953 0           DEBUG > 4 and print "That's a non-dynamic pod search.\n";
954             } elsif ( @dynamic_pod ) {
955 0           $self->aside("Hm, I found some Pod from that search!\n");
956 0           my ($buffd, $buffer) = $self->new_tempfile('pod', 'dyn');
957 0 0 0       if ( $] >= 5.008 && $self->opt_L ) {
958 0           binmode($buffd, ":encoding(UTF-8)");
959 0           print $buffd "=encoding utf8\n\n";
960             }
961              
962 0           push @{ $self->{'temp_file_list'} }, $buffer;
  0            
963             # I.e., it MIGHT be deleted at the end.
964              
965 0   0       my $in_list = !$self->not_dynamic && $self->opt_f || $self->opt_v || $self->opt_a;
966              
967 0 0         print $buffd "=over 8\n\n" if $in_list;
968 0 0         print $buffd @dynamic_pod or $self->die( "Can't print $buffer: $!" );
969 0 0         print $buffd "=back\n" if $in_list;
970              
971 0 0         close $buffd or $self->die( "Can't close $buffer: $!" );
972              
973 0           @$found_things = $buffer;
974             # Yes, so found_things never has more than one thing in
975             # it, by time we leave here
976              
977 0           $self->add_formatter_option('__filter_nroff' => 1);
978              
979             } else {
980 0           @$found_things = ();
981 0           $self->aside("I found no Pod from that search!\n");
982             }
983              
984 0           return;
985             }
986              
987             #..........................................................................
988              
989             sub not_dynamic {
990 0     0 0   my ($self,$value) = @_;
991 0 0         $self->{__not_dynamic} = $value if @_ == 2;
992 0           return $self->{__not_dynamic};
993             }
994              
995             #..........................................................................
996              
997             sub add_formatter_option { # $self->add_formatter_option('key' => 'value');
998 0     0 0   my $self = shift;
999 0 0         push @{ $self->{'formatter_switches'} }, [ @_ ] if @_;
  0            
1000              
1001             DEBUG > 3 and printf "Formatter switches now: [%s]\n",
1002 0           join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
1003              
1004 0           return;
1005             }
1006              
1007             #.........................................................................
1008              
1009             sub new_translator { # $tr = $self->new_translator($lang);
1010 0     0 0   my $self = shift;
1011 0           my $lang = shift;
1012              
1013 0           local @INC = @INC;
1014 0 0         pop @INC if $INC[-1] eq '.';
1015 0           my $pack = 'POD2::' . uc($lang);
1016 0           eval "require $pack";
1017 0 0 0       if ( !$@ && $pack->can('new') ) {
1018 0           return $pack->new();
1019             }
1020              
1021 0           eval { require POD2::Base };
  0            
1022 0 0         return if $@;
1023              
1024 0           return POD2::Base->new({ lang => $lang });
1025             }
1026              
1027             #.........................................................................
1028              
1029             sub add_translator { # $self->add_translator($lang);
1030 0     0 0   my $self = shift;
1031 0           for my $lang (@_) {
1032 0           my $tr = $self->new_translator($lang);
1033 0 0         if ( defined $tr ) {
1034 0           push @{ $self->{'translators'} }, $tr;
  0            
1035 0           push @{ $self->{'extra_search_dirs'} }, $tr->pod_dirs;
  0            
1036              
1037 0           $self->aside( "translator for '$lang' loaded\n" );
1038             } else {
1039             # non-installed or bad translator package
1040 0           $self->warn( "Perldoc cannot load translator package for '$lang': ignored\n" );
1041             }
1042              
1043             }
1044 0           return;
1045             }
1046              
1047             #..........................................................................
1048              
1049             sub open_fh {
1050 0     0 0   my ($self, $op, $path) = @_;
1051              
1052 0 0         open my $fh, $op, $path or $self->die("Couldn't open $path: $!");
1053 0           return $fh;
1054             }
1055              
1056             sub set_encoding {
1057 0     0 0   my ($self, $fh, $encoding) = @_;
1058              
1059 0 0         if ( $encoding =~ /utf-?8/i ) {
1060 0           $encoding = ":encoding(UTF-8)";
1061             }
1062             else {
1063 0           $encoding = ":encoding($encoding)";
1064             }
1065              
1066 0 0         if ( $] < 5.008 ) {
1067 0           $self->aside("Your old perl doesn't have proper unicode support.");
1068             }
1069             else {
1070 0           binmode($fh, $encoding);
1071             }
1072              
1073 0           return $fh;
1074             }
1075              
1076             sub search_perlvar {
1077 0     0 0   my($self, $found_things, $pod) = @_;
1078              
1079 0           my $opt = $self->opt_v;
1080              
1081 0 0         if ( $opt !~ /^ (?: [\@\%\$]\S+ | [A-Z]\w* ) $/x ) {
1082 0           CORE::die( "'$opt' does not look like a Perl variable\n" );
1083             }
1084              
1085 0           DEBUG > 2 and print "Search: @$found_things\n";
1086              
1087 0           my $perlvar = shift @$found_things;
1088 0           my $fh = $self->open_fh("<", $perlvar);
1089              
1090 0 0 0       if ( $opt ne '$0' && $opt =~ /^\$\d+$/ ) { # handle $1, $2, ...
1091 0           $opt = '$>';
1092             }
1093 0           my $search_re = quotemeta($opt);
1094              
1095 0           DEBUG > 2 and
1096             print "Going to perlvar-scan for $search_re in $perlvar\n";
1097              
1098             # Skip introduction
1099 0           local $_;
1100 0           my $enc;
1101 0           while (<$fh>) {
1102 0 0         $enc = $1 if /^=encoding\s+(\S+)/;
1103 0 0         last if /^=over 8/;
1104             }
1105              
1106 0 0         $fh = $self->set_encoding($fh, $enc) if $enc;
1107              
1108             # Look for our variable
1109 0           my $found = 0;
1110 0           my $inheader = 1;
1111 0           my $inlist = 0;
1112 0           while (<$fh>) {
1113 0 0         last if /^=head2 Error Indicators/;
1114             # \b at the end of $` and friends borks things!
1115 0 0         if ( m/^=item\s+$search_re\s/ ) {
    0          
    0          
1116 0           $found = 1;
1117             }
1118             elsif (/^=item/) {
1119 0 0 0       last if $found && !$inheader && !$inlist;
      0        
1120             }
1121             elsif (!/^\s+$/) { # not a blank line
1122 0 0         if ( $found ) {
1123 0           $inheader = 0; # don't accept more =item (unless inlist)
1124             }
1125             else {
1126 0           @$pod = (); # reset
1127 0           $inheader = 1; # start over
1128 0           next;
1129             }
1130             }
1131              
1132 0 0         if (/^=over/) {
    0          
1133 0           ++$inlist;
1134             }
1135             elsif (/^=back/) {
1136 0 0 0       last if $found && !$inheader && !$inlist;
      0        
1137 0           --$inlist;
1138             }
1139 0           push @$pod, $_;
1140             # ++$found if /^\w/; # found descriptive text
1141             }
1142 0 0         @$pod = () unless $found;
1143 0 0         if (!@$pod) {
1144 0           CORE::die( "No documentation for perl variable '$opt' found\n" );
1145             }
1146 0 0         close $fh or $self->die( "Can't close $perlvar: $!" );
1147              
1148 0           return;
1149             }
1150              
1151             #..........................................................................
1152              
1153             sub search_perlop {
1154 0     0 0   my ($self,$found_things,$pod) = @_;
1155              
1156 0           $self->not_dynamic( 1 );
1157              
1158 0           my $perlop = shift @$found_things;
1159             # XXX FIXME: getting filehandles should probably be done in a single place
1160             # especially since we need to support UTF8 or other encoding when dealing
1161             # with perlop, perlfunc, perlapi, perlfaq[1-9]
1162 0           my $fh = $self->open_fh('<', $perlop);
1163              
1164 0           my $thing = $self->opt_f;
1165              
1166 0           my $previous_line;
1167 0           my $push = 0;
1168 0           my $seen_item = 0;
1169 0           my $skip = 1;
1170              
1171 0           while( my $line = <$fh> ) {
1172 0 0         $line =~ /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1173             # only start search after we hit the operator section
1174 0 0         if ($line =~ m!^X!) {
1175 0           $skip = 0;
1176             }
1177              
1178 0 0         next if $skip;
1179              
1180             # strategy is to capture the previous line until we get a match on X<$thingy>
1181             # if the current line contains X<$thingy>, then we push "=over", the previous line,
1182             # the current line and keep pushing current line until we see a ^X,
1183             # then we chop off final line from @$pod and add =back
1184             #
1185             # At that point, Bob's your uncle.
1186              
1187 0 0 0       if ( $line =~ m!X<+\s*\Q$thing\E\s*>+!) {
    0 0        
    0 0        
    0          
1188 0 0         if ( $previous_line ) {
1189 0           push @$pod, "=over 8\n\n", $previous_line;
1190 0           $previous_line = "";
1191             }
1192 0           push @$pod, $line;
1193 0           $push = 1;
1194              
1195             }
1196             elsif ( $push and $line =~ m!^=item\s*.*$! ) {
1197 0           $seen_item = 1;
1198             }
1199             elsif ( $push and $seen_item and $line =~ m!^X<+\s*[ a-z,?-]+\s*>+!) {
1200 0           $push = 0;
1201 0           $seen_item = 0;
1202 0           last;
1203             }
1204             elsif ( $push ) {
1205 0           push @$pod, $line;
1206             }
1207              
1208             else {
1209 0           $previous_line = $line;
1210             }
1211              
1212             } #end while
1213              
1214             # we overfilled by 1 line, so pop off final array element if we have any
1215 0 0         if ( scalar @$pod ) {
1216 0           pop @$pod;
1217              
1218             # and add the =back
1219 0           push @$pod, "\n\n=back\n";
1220 0           DEBUG > 8 and print "PERLOP POD --->" . (join "", @$pod) . "<---\n";
1221             }
1222             else {
1223 0           DEBUG > 4 and print "No pod from perlop\n";
1224             }
1225              
1226 0           close $fh;
1227              
1228 0           return;
1229             }
1230              
1231             #..........................................................................
1232              
1233             sub search_perlapi {
1234 0     0 0   my($self, $found_things, $pod) = @_;
1235              
1236 0           DEBUG > 2 and print "Search: @$found_things\n";
1237              
1238 0           my $perlapi = shift @$found_things;
1239 0           my $fh = $self->open_fh('<', $perlapi);
1240              
1241 0           my $search_re = quotemeta($self->opt_a);
1242              
1243 0           DEBUG > 2 and
1244             print "Going to perlapi-scan for $search_re in $perlapi\n";
1245              
1246 0           local $_;
1247              
1248             # Look for our function
1249 0           my $found = 0;
1250 0           my $inlist = 0;
1251              
1252 0           my @related;
1253             my $related_re;
1254 0           while (<$fh>) {
1255 0 0         /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1256              
1257 0 0 0       if ( m/^=item\s+$search_re\b/ ) {
    0 0        
    0          
    0          
1258 0           $found = 1;
1259             }
1260             elsif (@related > 1 and /^=item/) {
1261 0   0       $related_re ||= join "|", @related;
1262 0 0         if (m/^=item\s+(?:$related_re)\b/) {
1263 0           $found = 1;
1264             }
1265             else {
1266 0           last;
1267             }
1268             }
1269             elsif (/^=item/) {
1270 0 0 0       last if $found > 1 and not $inlist;
1271             }
1272             elsif ($found and /^X<[^>]+>/) {
1273 0           push @related, m/X<([^>]+)>/g;
1274             }
1275 0 0         next unless $found;
1276 0 0         if (/^=over/) {
    0          
1277 0           ++$inlist;
1278             }
1279             elsif (/^=back/) {
1280 0 0 0       last if $found > 1 and not $inlist;
1281 0           --$inlist;
1282             }
1283 0           push @$pod, $_;
1284 0 0         ++$found if /^\w/; # found descriptive text
1285             }
1286              
1287 0 0         if (!@$pod) {
1288 0           CORE::die( sprintf
1289             "No documentation for perl api function '%s' found\n",
1290             $self->opt_a )
1291             ;
1292             }
1293 0 0         close $fh or $self->die( "Can't open $perlapi: $!" );
1294              
1295 0           return;
1296             }
1297              
1298             #..........................................................................
1299              
1300             sub search_perlfunc {
1301 0     0 0   my($self, $found_things, $pod) = @_;
1302              
1303 0           DEBUG > 2 and print "Search: @$found_things\n";
1304              
1305 0           my $pfunc = shift @$found_things;
1306 0           my $fh = $self->open_fh("<", $pfunc); # "Funk is its own reward"
1307              
1308             # Functions like -r, -e, etc. are listed under `-X'.
1309 0 0         my $search_re = ($self->opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/)
1310             ? '(?:I<)?-X' : quotemeta($self->opt_f) ;
1311              
1312 0           DEBUG > 2 and
1313             print "Going to perlfunc-scan for $search_re in $pfunc\n";
1314              
1315 0           my $re = 'Alphabetical Listing of Perl Functions';
1316              
1317             # Check available translator or backup to default (english)
1318 0 0 0       if ( $self->opt_L && defined $self->{'translators'}->[0] ) {
1319 0           my $tr = $self->{'translators'}->[0];
1320 0 0         $re = $tr->search_perlfunc_re if $tr->can('search_perlfunc_re');
1321 0 0         if ( $] < 5.008 ) {
1322 0           $self->aside("Your old perl doesn't really have proper unicode support.");
1323             }
1324             }
1325              
1326             # Skip introduction
1327 0           local $_;
1328 0           while (<$fh>) {
1329 0 0         /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1330 0 0         last if /^=head2 (?:$re|Alphabetical Listing of Perl Functions)/;
1331             }
1332              
1333             # Look for our function
1334 0           my $found = 0;
1335 0           my $inlist = 0;
1336              
1337 0           my @perlops = qw(m q qq qr qx qw s tr y);
1338              
1339 0           my @related;
1340             my $related_re;
1341 0           while (<$fh>) { # "The Mothership Connection is here!"
1342 0 0         last if( grep{ $self->opt_f eq $_ }@perlops );
  0            
1343              
1344 0 0 0       if ( /^=over/ and not $found ) {
    0 0        
      0        
1345 0           ++$inlist;
1346             }
1347             elsif ( /^=back/ and not $found and $inlist ) {
1348 0           --$inlist;
1349             }
1350              
1351              
1352 0 0 0       if ( m/^=item\s+$search_re\b/ and $inlist < 2 ) {
    0 0        
    0 0        
    0          
1353 0           $found = 1;
1354             }
1355             elsif (@related > 1 and /^=item/) {
1356 0   0       $related_re ||= join "|", @related;
1357 0 0         if (m/^=item\s+(?:$related_re)\b/) {
1358 0           $found = 1;
1359             }
1360             else {
1361 0 0 0       last if $found > 1 and $inlist < 2;
1362             }
1363             }
1364             elsif (/^=item|^=back/) {
1365 0 0 0       last if $found > 1 and $inlist < 2;
1366             }
1367             elsif ($found and /^X<[^>]+>/) {
1368 0           push @related, m/X<([^>]+)>/g;
1369             }
1370 0 0         next unless $found;
1371 0 0         if (/^=over/) {
    0          
1372 0           ++$inlist;
1373             }
1374             elsif (/^=back/) {
1375 0           --$inlist;
1376             }
1377 0           push @$pod, $_;
1378 0 0         ++$found if /^\w/; # found descriptive text
1379             }
1380              
1381 0 0         if( !@$pod ){
1382 0           $self->search_perlop( $found_things, $pod );
1383             }
1384              
1385 0 0         if (!@$pod) {
1386 0           CORE::die( sprintf
1387             "No documentation for perl function '%s' found\n",
1388             $self->opt_f )
1389             ;
1390             }
1391 0 0         close $fh or $self->die( "Can't close $pfunc: $!" );
1392              
1393 0           return;
1394             }
1395              
1396             #..........................................................................
1397              
1398             sub search_perlfaqs {
1399 0     0 0   my( $self, $found_things, $pod) = @_;
1400              
1401 0           my $found = 0;
1402 0           my %found_in;
1403 0           my $search_key = $self->opt_q;
1404              
1405 0 0         my $rx = eval { qr/$search_key/ }
  0            
1406             or $self->die( <
1407             Invalid regular expression '$search_key' given as -q pattern:
1408             $@
1409             Did you mean \\Q$search_key ?
1410              
1411             EOD
1412              
1413 0           local $_;
1414 0           foreach my $file (@$found_things) {
1415 0 0         $self->die( "invalid file spec: $!" ) if $file =~ /[<>|]/;
1416 0           my $fh = $self->open_fh("<", $file);
1417 0           while (<$fh>) {
1418 0 0         /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1419 0 0         if ( m/^=head2\s+.*(?:$search_key)/i ) {
    0          
1420 0           $found = 1;
1421 0 0         push @$pod, "=head1 Found in $file\n\n" unless $found_in{$file}++;
1422             }
1423             elsif (/^=head[12]/) {
1424 0           $found = 0;
1425             }
1426 0 0         next unless $found;
1427 0           push @$pod, $_;
1428             }
1429 0           close($fh);
1430             }
1431 0 0         CORE::die("No documentation for perl FAQ keyword '$search_key' found\n")
1432             unless @$pod;
1433              
1434 0 0         if ( $self->opt_l ) {
1435 0           CORE::die((join "\n", keys %found_in) . "\n");
1436             }
1437 0           return;
1438             }
1439              
1440              
1441             #..........................................................................
1442              
1443             sub render_findings {
1444             # Return the filename to open
1445              
1446 0     0 0   my($self, $found_things) = @_;
1447              
1448 0   0       my $formatter_class = $self->{'formatter_class'}
1449             || $self->die( "No formatter class set!?" );
1450 0 0         my $formatter = $formatter_class->can('new')
1451             ? $formatter_class->new
1452             : $formatter_class
1453             ;
1454              
1455 0 0         if(! @$found_things) {
    0          
1456 0           $self->die( "Nothing found?!" );
1457             # should have been caught before here
1458             } elsif(@$found_things > 1) {
1459 0           $self->warn(
1460             "Perldoc is only really meant for reading one document at a time.\n",
1461             "So these parameters are being ignored: ",
1462             join(' ', @$found_things[1 .. $#$found_things] ),
1463             "\n" );
1464             }
1465              
1466 0           my $file = $found_things->[0];
1467              
1468             DEBUG > 3 and printf "Formatter switches now: [%s]\n",
1469 0           join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
1470              
1471             # Set formatter options:
1472 0 0         if( ref $formatter ) {
1473 0 0         foreach my $f (@{ $self->{'formatter_switches'} || [] }) {
  0            
1474 0           my($switch, $value, $silent_fail) = @$f;
1475 0 0         if( $formatter->can($switch) ) {
1476 0 0         eval { $formatter->$switch( defined($value) ? $value : () ) };
  0            
1477 0 0         $self->warn( "Got an error when setting $formatter_class\->$switch:\n$@\n" )
1478             if $@;
1479             } else {
1480 0 0 0       if( $silent_fail or $switch =~ m/^__/s ) {
1481 0           DEBUG > 2 and print "Formatter $formatter_class doesn't support $switch\n";
1482             } else {
1483 0           $self->warn( "$formatter_class doesn't recognize the $switch switch.\n" );
1484             }
1485             }
1486             }
1487             }
1488              
1489 0   0       $self->{'output_is_binary'} =
1490             $formatter->can('write_with_binmode') && $formatter->write_with_binmode;
1491              
1492 0 0 0       if( $self->{podnames} and exists $self->{podnames}{$file} and
      0        
1493             $formatter->can('name') ) {
1494 0           $formatter->name($self->{podnames}{$file});
1495             }
1496              
1497 0   0       my ($out_fh, $out) = $self->new_output_file(
1498             ( $formatter->can('output_extension') && $formatter->output_extension )
1499             || undef,
1500             $self->useful_filename_bit,
1501             );
1502              
1503             # Now, finally, do the formatting!
1504             {
1505 0           local $^W = $^W;
  0            
1506 0 0         if(DEBUG() or $self->opt_D) {
1507             # feh, let 'em see it
1508             } else {
1509 0           $^W = 0;
1510             # The average user just has no reason to be seeing
1511             # $^W-suppressible warnings from the formatting!
1512             }
1513              
1514 0           eval { $formatter->parse_from_file( $file, $out_fh ) };
  0            
1515             }
1516              
1517 0 0         $self->warn( "Error while formatting with $formatter_class:\n $@\n" ) if $@;
1518 0           DEBUG > 2 and print "Back from formatting with $formatter_class\n";
1519              
1520 0 0         close $out_fh
1521             or $self->warn( "Can't close $out: $!\n(Did $formatter already close it?)" );
1522 0           sleep 0; sleep 0; sleep 0;
  0            
  0            
1523             # Give the system a few timeslices to meditate on the fact
1524             # that the output file does in fact exist and is closed.
1525              
1526 0           $self->unlink_if_temp_file($file);
1527              
1528 0 0         unless( -s $out ) {
1529 0 0         if( $formatter->can( 'if_zero_length' ) ) {
1530             # Basically this is just a hook for Pod::Simple::Checker; since
1531             # what other class could /happily/ format an input file with Pod
1532             # as a 0-length output file?
1533 0           $formatter->if_zero_length( $file, $out, $out_fh );
1534             } else {
1535 0           $self->warn( "Got a 0-length file from $$found_things[0] via $formatter_class!?\n" );
1536             }
1537             }
1538              
1539 0           DEBUG and print "Finished writing to $out.\n";
1540 0 0         return($out, $formatter) if wantarray;
1541 0           return $out;
1542             }
1543              
1544             #..........................................................................
1545              
1546             sub unlink_if_temp_file {
1547             # Unlink the specified file IFF it's in the list of temp files.
1548             # Really only used in the case of -f / -q things when we can
1549             # throw away the dynamically generated source pod file once
1550             # we've formatted it.
1551             #
1552 0     0 0   my($self, $file) = @_;
1553 0 0 0       return unless defined $file and length $file;
1554              
1555 0   0       my $temp_file_list = $self->{'temp_file_list'} || return;
1556 0 0         if(grep $_ eq $file, @$temp_file_list) {
1557 0           $self->aside("Unlinking $file\n");
1558 0 0         unlink($file) or $self->warn( "Odd, couldn't unlink $file: $!" );
1559             } else {
1560 0           DEBUG > 1 and print "$file isn't a temp file, so not unlinking.\n";
1561             }
1562 0           return;
1563             }
1564              
1565             #..........................................................................
1566              
1567              
1568             sub after_rendering {
1569 0     0 0   my $self = $_[0];
1570 0 0         $self->after_rendering_VMS if $self->is_vms;
1571 0 0         $self->after_rendering_MSWin32 if $self->is_mswin32;
1572 0 0         $self->after_rendering_Dos if $self->is_dos;
1573 0 0         $self->after_rendering_OS2 if $self->is_os2;
1574 0           return;
1575             }
1576              
1577 0     0 0   sub after_rendering_VMS { return }
1578 0     0 0   sub after_rendering_Dos { return }
1579 0     0 0   sub after_rendering_OS2 { return }
1580 0     0 0   sub after_rendering_MSWin32 { return }
1581              
1582             #..........................................................................
1583             # : : : : : : : : :
1584             #..........................................................................
1585              
1586             sub minus_f_nocase { # i.e., do like -f, but without regard to case
1587              
1588 0     0 0   my($self, $dir, $file) = @_;
1589 0           my $path = catfile($dir,$file);
1590 0 0 0       return $path if -f $path and -r _;
1591              
1592 0 0 0       if(!$self->opt_i
      0        
      0        
      0        
1593             or $self->is_vms or $self->is_mswin32
1594             or $self->is_dos or $self->is_os2
1595             ) {
1596             # On a case-forgiving file system, or if case is important,
1597             # that is it, all we can do.
1598 0 0         $self->warn( "Ignored $path: unreadable\n" ) if -f _;
1599 0           return '';
1600             }
1601              
1602 0           local *DIR;
1603 0           my @p = ($dir);
1604 0           my($p,$cip);
1605 0           foreach $p (splitdir $file){
1606 0           my $try = catfile @p, $p;
1607 0           $self->aside("Scrutinizing $try...\n");
1608 0           stat $try;
1609 0 0 0       if (-d _) {
    0 0        
    0          
    0          
1610 0           push @p, $p;
1611 0 0         if ( $p eq $self->{'target'} ) {
1612 0           my $tmp_path = catfile @p;
1613 0           my $path_f = 0;
1614 0           for (@{ $self->{'found'} }) {
  0            
1615 0 0         $path_f = 1 if $_ eq $tmp_path;
1616             }
1617 0 0         push (@{ $self->{'found'} }, $tmp_path) unless $path_f;
  0            
1618 0           $self->aside( "Found as $tmp_path but directory\n" );
1619             }
1620             }
1621             elsif (-f _ && -r _ && lc($try) eq lc($path)) {
1622 0           return $try;
1623             }
1624             elsif (-f _) {
1625 0           $self->warn( "Ignored $try: unreadable or file/dir mismatch\n" );
1626             }
1627             elsif (-d catdir(@p)) { # at least we see the containing directory!
1628 0           my $found = 0;
1629 0           my $lcp = lc $p;
1630 0           my $p_dirspec = catdir(@p);
1631 0 0         opendir DIR, $p_dirspec or $self->die( "opendir $p_dirspec: $!" );
1632 0           while(defined( $cip = readdir(DIR) )) {
1633 0 0         if (lc $cip eq $lcp){
1634 0           $found++;
1635 0           last; # XXX stop at the first? what if there's others?
1636             }
1637             }
1638 0 0         closedir DIR or $self->die( "closedir $p_dirspec: $!" );
1639 0 0         return "" unless $found;
1640              
1641 0           push @p, $cip;
1642 0           my $p_filespec = catfile(@p);
1643 0 0 0       return $p_filespec if -f $p_filespec and -r _;
1644 0 0         $self->warn( "Ignored $p_filespec: unreadable\n" ) if -f _;
1645             }
1646             }
1647 0           return "";
1648             }
1649              
1650             #..........................................................................
1651              
1652             sub pagers_guessing {
1653             # TODO: This whole subroutine needs to be rewritten. It's semi-insane
1654             # right now.
1655              
1656 0     0 0   my $self = shift;
1657              
1658 0           my @pagers;
1659 0           push @pagers, $self->pagers;
1660 0           $self->{'pagers'} = \@pagers;
1661              
1662 0 0         if ($self->is_mswin32) {
    0          
    0          
    0          
1663 0           push @pagers, qw( more< less notepad );
1664 0 0         unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
1665             }
1666             elsif ($self->is_vms) {
1667 0           push @pagers, qw( most more less type/page );
1668             }
1669             elsif ($self->is_dos) {
1670 0           push @pagers, qw( less.exe more.com< );
1671 0 0         unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
1672             }
1673             elsif ( $self->is_amigaos) {
1674 0           push @pagers, qw( /SYS/Utilities/MultiView /SYS/Utilities/More /C/TYPE );
1675 0 0         unshift @pagers, "$ENV{PAGER}" if $ENV{PAGER};
1676             }
1677             else {
1678 0 0         if ($self->is_os2) {
1679 0           unshift @pagers, 'less', 'cmd /c more <';
1680             }
1681 0           push @pagers, qw( more less pg view cat );
1682 0 0         unshift @pagers, "$ENV{PAGER} <" if $ENV{PAGER};
1683             }
1684              
1685 0 0         if ($self->is_cygwin) {
1686 0 0 0       if (($pagers[0] eq 'less') || ($pagers[0] eq '/usr/bin/less')) {
1687 0           unshift @pagers, '/usr/bin/less -isrR';
1688 0 0         unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
1689             }
1690             }
1691              
1692 0 0         if ( $self->opt_m ) {
1693             unshift @pagers, "$ENV{PERLDOC_SRC_PAGER}" if $ENV{PERLDOC_SRC_PAGER}
1694 0 0         }
1695             else {
1696 0 0         unshift @pagers, "$ENV{MANPAGER} <" if $ENV{MANPAGER};
1697 0 0         unshift @pagers, "$ENV{PERLDOC_PAGER} <" if $ENV{PERLDOC_PAGER};
1698             }
1699              
1700 0           $self->aside("Pagers: ", (join ", ", @pagers));
1701              
1702 0           return;
1703             }
1704              
1705             #..........................................................................
1706              
1707             sub page_module_file {
1708 0     0 0   my($self, @found) = @_;
1709              
1710             # Security note:
1711             # Don't ever just pass this off to anything like MSWin's "start.exe",
1712             # since we might be calling on a .pl file, and we wouldn't want that
1713             # to actually /execute/ the file that we just want to page thru!
1714             # Also a consideration if one were to use a web browser as a pager;
1715             # doing so could trigger the browser's MIME mapping for whatever
1716             # it thinks .pm/.pl/whatever is. Probably just a (useless and
1717             # annoying) "Save as..." dialog, but potentially executing the file
1718             # in question -- particularly in the case of MSIE and it's, ahem,
1719             # occasionally hazy distinction between OS-local extension
1720             # associations, and browser-specific MIME mappings.
1721              
1722 0 0         if(@found > 1) {
1723 0           $self->warn(
1724             "Perldoc is only really meant for reading one document at a time.\n" .
1725             "So these files are being ignored: " .
1726             join(' ', @found[1 .. $#found] ) .
1727             "\n" )
1728             }
1729              
1730 0           return $self->page($found[0], $self->{'output_to_stdout'}, $self->pagers);
1731              
1732             }
1733              
1734             #..........................................................................
1735              
1736             sub check_file {
1737 0     0 0   my($self, $dir, $file) = @_;
1738              
1739 0 0         unless( ref $self ) {
1740             # Should never get called:
1741 0           $Carp::Verbose = 1;
1742 0           require Carp;
1743 0           Carp::croak( join '',
1744             "Crazy ", __PACKAGE__, " error:\n",
1745             "check_file must be an object_method!\n",
1746             "Aborting"
1747             );
1748             }
1749              
1750 0 0 0       if(length $dir and not -d $dir) {
1751 0           DEBUG > 3 and print " No dir $dir -- skipping.\n";
1752 0           return "";
1753             }
1754              
1755 0           my $path = $self->minus_f_nocase($dir,$file);
1756 0 0 0       if( length $path and ($self->opt_m ? $self->isprintable($path)
    0          
1757             : $self->containspod($path)) ) {
1758 0           DEBUG > 3 and print
1759             " The file $path indeed looks promising!\n";
1760 0           return $path;
1761             }
1762 0           DEBUG > 3 and print " No good: $file in $dir\n";
1763              
1764 0           return "";
1765             }
1766              
1767             sub isprintable {
1768 0     0 0   my($self, $file, $readit) = @_;
1769 0           my $size= 1024;
1770 0           my $maxunprintfrac= 0.2; # tolerate some unprintables for UTF-8 comments etc.
1771              
1772 0 0 0       return 1 if !$readit && $file =~ /\.(?:pl|pm|pod|cmd|com|bat)\z/i;
1773              
1774 0           my $data;
1775 0           local($_);
1776 0           my $fh = $self->open_fh("<", $file);
1777 0           read $fh, $data, $size;
1778 0           close $fh;
1779 0           $size= length($data);
1780 0           $data =~ tr/\x09-\x0D\x20-\x7E//d;
1781 0           return length($data) <= $size*$maxunprintfrac;
1782             }
1783              
1784             #..........................................................................
1785              
1786             sub containspod {
1787 0     0 0   my($self, $file, $readit) = @_;
1788 0 0 0       return 1 if !$readit && $file =~ /\.pod\z/i;
1789              
1790              
1791             # Under cygwin the /usr/bin/perl is legal executable, but
1792             # you cannot open a file with that name. It must be spelled
1793             # out as "/usr/bin/perl.exe".
1794             #
1795             # The following if-case under cygwin prevents error
1796             #
1797             # $ perldoc perl
1798             # Cannot open /usr/bin/perl: no such file or directory
1799             #
1800             # This would work though
1801             #
1802             # $ perldoc perl.pod
1803              
1804 0 0 0       if ( $self->is_cygwin and -x $file and -f "$file.exe" )
      0        
1805             {
1806 0 0         $self->warn( "Cygwin $file.exe search skipped\n" ) if DEBUG or $self->opt_D;
1807 0           return 0;
1808             }
1809              
1810 0           local($_);
1811 0           my $fh = $self->open_fh("<", $file);
1812 0           while (<$fh>) {
1813 0 0         if (/^=head/) {
1814 0 0         close($fh) or $self->die( "Can't close $file: $!" );
1815 0           return 1;
1816             }
1817             }
1818 0 0         close($fh) or $self->die( "Can't close $file: $!" );
1819 0           return 0;
1820             }
1821              
1822             #..........................................................................
1823              
1824             sub maybe_extend_searchpath {
1825 0     0 0   my $self = shift;
1826              
1827             # Does this look like a module or extension directory?
1828              
1829 0 0 0       if (-f "Makefile.PL" || -f "Build.PL") {
1830              
1831 0           push @{$self->{search_path} }, '.','lib';
  0            
1832              
1833             # don't add if superuser
1834 0 0 0       if ($< && $> && -d "blib") { # don't be looking too hard now!
      0        
1835 0           push @{ $self->{search_path} }, 'blib';
  0            
1836 0 0 0       $self->warn( $@ ) if $@ && $self->opt_D;
1837             }
1838             }
1839              
1840 0           return;
1841             }
1842              
1843             #..........................................................................
1844              
1845             sub new_output_file {
1846 0     0 0   my $self = shift;
1847 0           my $outspec = $self->opt_d; # Yes, -d overrides all else!
1848             # So don't call this twice per format-job!
1849              
1850 0 0 0       return $self->new_tempfile(@_) unless defined $outspec and length $outspec;
1851              
1852             # Otherwise open a write-handle on opt_d!f
1853              
1854 0           DEBUG > 3 and print "About to try writing to specified output file $outspec\n";
1855 0           my $fh = $self->open_fh(">", $outspec);
1856              
1857 0           DEBUG > 3 and print "Successfully opened $outspec\n";
1858 0 0         binmode($fh) if $self->{'output_is_binary'};
1859 0           return($fh, $outspec);
1860             }
1861              
1862             #..........................................................................
1863              
1864             sub useful_filename_bit {
1865             # This tries to provide a meaningful bit of text to do with the query,
1866             # such as can be used in naming the file -- since if we're going to be
1867             # opening windows on temp files (as a "pager" may well do!) then it's
1868             # better if the temp file's name (which may well be used as the window
1869             # title) isn't ALL just random garbage!
1870             # In other words "perldoc_LWPSimple_2371981429" is a better temp file
1871             # name than "perldoc_2371981429". So this routine is what tries to
1872             # provide the "LWPSimple" bit.
1873             #
1874 0     0 0   my $self = shift;
1875 0   0       my $pages = $self->{'pages'} || return undef;
1876 0 0         return undef unless @$pages;
1877              
1878 0           my $chunk = $pages->[0];
1879 0 0         return undef unless defined $chunk;
1880 0           $chunk =~ s/:://g;
1881 0           $chunk =~ s/\.\w+$//g; # strip any extension
1882 0 0         if( $chunk =~ m/([^\#\\:\/\$]+)$/s ) { # get basename, if it's a file
1883 0           $chunk = $1;
1884             } else {
1885 0           return undef;
1886             }
1887 0           $chunk =~ s/[^a-zA-Z0-9]+//g; # leave ONLY a-zA-Z0-9 things!
1888 0 0         $chunk = substr($chunk, -10) if length($chunk) > 10;
1889 0           return $chunk;
1890             }
1891              
1892             #..........................................................................
1893              
1894             sub new_tempfile { # $self->new_tempfile( [$suffix, [$infix] ] )
1895 0     0 0   my $self = shift;
1896              
1897 0           ++$Temp_Files_Created;
1898              
1899 0           require File::Temp;
1900 0           return File::Temp::tempfile(UNLINK => 1);
1901             }
1902              
1903             #..........................................................................
1904              
1905             sub page { # apply a pager to the output file
1906 0     0 0   my ($self, $output, $output_to_stdout, @pagers) = @_;
1907 0 0         if ($output_to_stdout) {
1908 0           $self->aside("Sending unpaged output to STDOUT.\n");
1909 0           my $fh = $self->open_fh("<", $output);
1910 0           local $_;
1911 0           while (<$fh>) {
1912 0 0         print or $self->die( "Can't print to stdout: $!" );
1913             }
1914 0 0         close $fh or $self->die( "Can't close while $output: $!" );
1915 0           $self->unlink_if_temp_file($output);
1916             } else {
1917             # On VMS, quoting prevents logical expansion, and temp files with no
1918             # extension get the wrong default extension (such as .LIS for TYPE)
1919              
1920 0 0         $output = VMS::Filespec::rmsexpand($output, '.') if $self->is_vms;
1921              
1922 0 0 0       $output =~ s{/}{\\}g if $self->is_mswin32 || $self->is_dos;
1923             # Altho "/" under MSWin is in theory good as a pathsep,
1924             # many many corners of the OS don't like it. So we
1925             # have to force it to be "\" to make everyone happy.
1926              
1927             # if we are on an amiga convert unix path to an amiga one
1928 0 0         $output =~ s/^\/(.*)\/(.*)/$1:$2/ if $self->is_amigaos;
1929              
1930 0           foreach my $pager (@pagers) {
1931 0           $self->aside("About to try calling $pager $output\n");
1932 0 0         if ($self->is_vms) {
    0          
1933 0 0         last if system("$pager $output") == 0;
1934             } elsif($self->is_amigaos) {
1935 0 0         last if system($pager, $output) == 0;
1936             } else {
1937 0 0         if ( $self->{'formatter_class'} =~ /ToTerm/i ) {
1938             # fix visible escape codes in ToTerm output
1939             # https://bugs.debian.org/758689
1940 0           $self->aside("Possibly changing environment variables for less or more pagers\n");
1941 0 0         $ENV{LESS} = defined $ENV{LESS} ? $ENV{LESS} : "-R";
1942             # Don't mess with the environment for MORE on Windows or DOS
1943 0 0 0       if ( ! $self->is_mswin32 || ! $self->is_dos ) {
1944             # On FreeBSD, the default pager is more.
1945 0 0         $ENV{MORE} = defined $ENV{MORE} ? $ENV{MORE} : "-R";
1946             }
1947 0 0         $self->aside("less environment: " . $ENV{LESS} ."\n") if $ENV{LESS};
1948 0 0         $self->aside("more environment: " . $ENV{MORE} ."\n") if $ENV{MORE};
1949             }
1950 0 0         last if system("$pager \"$output\"") == 0;
1951             }
1952             }
1953             }
1954 0           return;
1955             }
1956              
1957             #..........................................................................
1958              
1959             sub searchfor {
1960 0     0 0   my($self, $recurse,$s,@dirs) = @_;
1961 0           $s =~ s!::!/!g;
1962 0 0         $s = VMS::Filespec::unixify($s) if $self->is_vms;
1963 0 0 0       return $s if -f $s && $self->containspod($s);
1964 0           $self->aside( "Looking for $s in @dirs\n" );
1965 0           my $ret;
1966             my $i;
1967 0           my $dir;
1968 0           $self->{'target'} = (splitdir $s)[-1]; # XXX: why not use File::Basename?
1969 0           for ($i=0; $i<@dirs; $i++) {
1970 0           $dir = $dirs[$i];
1971 0 0         next unless -d $dir;
1972 0 0         ($dir = VMS::Filespec::unixpath($dir)) =~ s!/\z!! if $self->is_vms;
1973 0 0 0       if ( (! $self->opt_m && ( $ret = $self->check_file($dir,"$s.pod")))
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
1974             or ( $ret = $self->check_file($dir,"$s.pm"))
1975             or ( $ret = $self->check_file($dir,$s))
1976             or ( $self->is_vms and
1977             $ret = $self->check_file($dir,"$s.com"))
1978             or ( $self->is_os2 and
1979             $ret = $self->check_file($dir,"$s.cmd"))
1980             or ( ($self->is_mswin32 or $self->is_dos or $self->is_os2) and
1981             $ret = $self->check_file($dir,"$s.bat"))
1982             or ( $ret = $self->check_file("$dir/pod","$s.pod"))
1983             or ( $ret = $self->check_file("$dir/pod",$s))
1984             or ( $ret = $self->check_file("$dir/pods","$s.pod"))
1985             or ( $ret = $self->check_file("$dir/pods",$s))
1986             ) {
1987 0           DEBUG > 1 and print " Found $ret\n";
1988 0           return $ret;
1989             }
1990              
1991 0 0         if ($recurse) {
1992 0 0         opendir(D,$dir) or $self->die( "Can't opendir $dir: $!" );
1993             my @newdirs = map catfile($dir, $_), grep {
1994 0 0 0       not /^\.\.?\z/s and
  0            
1995             not /^auto\z/s and # save time! don't search auto dirs
1996             -d catfile($dir, $_)
1997             } readdir D;
1998 0 0         closedir(D) or $self->die( "Can't closedir $dir: $!" );
1999 0 0         next unless @newdirs;
2000             # what a wicked map!
2001 0 0         @newdirs = map((s/\.dir\z//,$_)[1],@newdirs) if $self->is_vms;
2002 0           $self->aside( "Also looking in @newdirs\n" );
2003 0           push(@dirs,@newdirs);
2004             }
2005             }
2006 0           return ();
2007             }
2008              
2009             #..........................................................................
2010             {
2011             my $already_asserted;
2012             sub assert_closing_stdout {
2013 0     0 0   my $self = shift;
2014              
2015 0 0         return if $already_asserted;
2016              
2017 0           eval q~ END { close(STDOUT) || CORE::die "Can't close STDOUT: $!" } ~;
2018             # What for? to let the pager know that nothing more will come?
2019              
2020 0 0         $self->die( $@ ) if $@;
2021 0           $already_asserted = 1;
2022 0           return;
2023             }
2024             }
2025              
2026             #..........................................................................
2027              
2028             sub tweak_found_pathnames {
2029 0     0 0   my($self, $found) = @_;
2030 0 0         if ($self->is_mswin32) {
2031 0           foreach (@$found) { s,/,\\,g }
  0            
2032             }
2033 0           foreach (@$found) { s,',\\',g } # RT 37347
  0            
2034 0           return;
2035             }
2036              
2037             #..........................................................................
2038             # : : : : : : : : :
2039             #..........................................................................
2040              
2041             sub am_taint_checking {
2042 0     0 0   my $self = shift;
2043 0 0         $self->die( "NO ENVIRONMENT?!?!" ) unless keys %ENV; # reset iterator along the way
2044 0           my($k,$v) = each %ENV;
2045 0           return is_tainted($v);
2046             }
2047              
2048             #..........................................................................
2049              
2050             sub is_tainted { # just a function
2051 0     0 0   my $arg = shift;
2052 0           my $nada = substr($arg, 0, 0); # zero-length!
2053 0           local $@; # preserve the caller's version of $@
2054 0           eval { eval "# $nada" };
  0            
2055 0           return length($@) != 0;
2056             }
2057              
2058             #..........................................................................
2059              
2060             sub drop_privs_maybe {
2061 0     0 0   my $self = shift;
2062              
2063 0           DEBUG and print "Attempting to drop privs...\n";
2064              
2065             # Attempt to drop privs if we should be tainting and aren't
2066 0 0 0       if (!( $self->is_vms || $self->is_mswin32 || $self->is_dos
      0        
      0        
      0        
2067             || $self->is_os2
2068             )
2069             && ($> == 0 || $< == 0)
2070             && !$self->am_taint_checking()
2071             ) {
2072 0           my $id = eval { getpwnam("nobody") };
  0            
2073 0 0         $id = eval { getpwnam("nouser") } unless defined $id;
  0            
2074 0 0         $id = -2 unless defined $id;
2075             #
2076             # According to Stevens' APUE and various
2077             # (BSD, Solaris, HP-UX) man pages, setting
2078             # the real uid first and effective uid second
2079             # is the way to go if one wants to drop privileges,
2080             # because if one changes into an effective uid of
2081             # non-zero, one cannot change the real uid any more.
2082             #
2083             # Actually, it gets even messier. There is
2084             # a third uid, called the saved uid, and as
2085             # long as that is zero, one can get back to
2086             # uid of zero. Setting the real-effective *twice*
2087             # helps in *most* systems (FreeBSD and Solaris)
2088             # but apparently in HP-UX even this doesn't help:
2089             # the saved uid stays zero (apparently the only way
2090             # in HP-UX to change saved uid is to call setuid()
2091             # when the effective uid is zero).
2092             #
2093 0           eval {
2094 0           $< = $id; # real uid
2095 0           $> = $id; # effective uid
2096 0           $< = $id; # real uid
2097 0           $> = $id; # effective uid
2098             };
2099 0 0 0       if( !$@ && $< && $> ) {
    0 0        
2100 0           DEBUG and print "OK, I dropped privileges.\n";
2101             } elsif( $self->opt_U ) {
2102 0           DEBUG and print "Couldn't drop privileges, but in -U mode, so feh."
2103             } else {
2104 0           DEBUG and print "Hm, couldn't drop privileges. Ah well.\n";
2105             # We used to die here; but that seemed pointless.
2106             }
2107             }
2108 0           return;
2109             }
2110              
2111             #..........................................................................
2112              
2113             1;
2114              
2115             __END__