File Coverage

blib/lib/Pod/Perldoc.pm
Criterion Covered Total %
statement 49 924 5.3
branch 18 624 2.8
condition 1 350 0.2
subroutine 15 88 17.0
pod 0 71 0.0
total 83 2057 4.0


line stmt bran cond sub pod time code
1 1     1   1136 use 5.006; # we use some open(X, "<", $y) syntax
  1         2  
2              
3             package Pod::Perldoc;
4 1     1   4 use strict;
  1         1  
  1         18  
5 1     1   10 use warnings;
  1         1  
  1         28  
6 1     1   3 use Config '%Config';
  1         1  
  1         35  
7              
8 1     1   3 use Fcntl; # for sysopen
  1         2  
  1         229  
9 1     1   4 use File::Basename qw(basename);
  1         1  
  1         57  
10 1     1   389 use File::Spec::Functions qw(catfile catdir splitdir);
  1         576  
  1         55  
11              
12 1         135 use vars qw($VERSION @Pagers $Bindir $Pod2man
13             $Temp_Files_Created $Temp_File_Lifetime
14 1     1   4 );
  1         1  
15             $VERSION = '3.28';
16              
17             #..........................................................................
18              
19             BEGIN { # Make a DEBUG constant very first thing...
20 1 50   1   3 unless(defined &DEBUG) {
21 1 50 50     7 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         17 *DEBUG = sub () {0};
26             }
27             }
28             }
29              
30 1     1   342 use Pod::Perldoc::GetOptsOO; # uses the DEBUG.
  1         2  
  1         24  
31 1     1   5 use Carp qw(croak carp);
  1         1  
  1         366  
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   6 *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       4 *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       104 *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   5 no strict 'refs';
  1         1  
  1         26  
96 1     1   3 *$subname = do{ use strict 'refs'; sub () { shift->_elem($subname, @_) } };
  1     0   1  
  1         1967  
  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   681 use Encode qw(decode_utf8);
  1         9739  
  1         11335  
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 0 0         if ( /^https/ ) {
857 0           print STDERR "You may need an SSL library (such as IO::Socket::SSL) for that URL.\n";
858             }
859             }
860 0           next;
861             }
862 0 0 0       if ($self->{'podidx'} && open(PODIDX, $self->{'podidx'})) {
863 0           my $searchfor = catfile split '::', $_;
864 0           $self->aside( "Searching for '$searchfor' in $self->{'podidx'}\n" );
865 0           local $_;
866 0           while () {
867 0           chomp;
868 0 0         push(@found, $_) if m,/$searchfor(?:\.(?:pod|pm))?\z,i;
869             }
870 0 0         close(PODIDX) or $self->die( "Can't close $$self{'podidx'}: $!" );
871 0           next;
872             }
873              
874 0           $self->aside( "Searching for $_\n" );
875              
876 0 0         if ($self->opt_F) {
877 0 0         next unless -r;
878 0 0 0       push @found, $_ if $self->opt_l or $self->opt_m or $self->containspod($_);
      0        
879 0           next;
880             }
881              
882 0           my @searchdirs;
883              
884             # prepend extra search directories (including language specific)
885 0           push @searchdirs, @{ $self->{'extra_search_dirs'} };
  0            
886              
887             # We must look both in @INC for library modules and in $bindir
888             # for executables, like h2xs or perldoc itself.
889 0           push @searchdirs, ($self->{'bindir'}, @{$self->{search_path}}, @INC);
  0            
890 0 0         unless ($self->opt_m) {
891 0 0         if ($self->is_vms) {
892 0           my($i,$trn);
893 0           for ($i = 0; $trn = $ENV{'DCL$PATH;'.$i}; $i++) {
894 0           push(@searchdirs,$trn);
895             }
896 0           push(@searchdirs,'perl_root:[lib.pods]') # installed pods
897             }
898             else {
899             push(@searchdirs, grep(-d, split($Config{path_sep},
900 0           $ENV{'PATH'})));
901             }
902             }
903 0           my @files = $self->searchfor(0,$_,@searchdirs);
904 0 0 0       if (@files) {
    0          
905 0           $self->aside( "Found as @files\n" );
906             }
907             # add "perl" prefix, so "perldoc foo" may find perlfoo.pod
908             elsif (BE_LENIENT and !/\W/ and @files = $self->searchfor(0, "perl$_", @searchdirs)) {
909 0           $self->aside( "Loosely found as @files\n" );
910             }
911             else {
912             # no match, try recursive search
913 0           @searchdirs = grep(!/^\.\z/s,@INC);
914 0 0         @files= $self->searchfor(1,$_,@searchdirs) if $self->opt_r;
915 0 0         if (@files) {
916 0           $self->aside( "Loosely found as @files\n" );
917             }
918             else {
919 0 0         print STDERR "No " .
920             ($self->opt_m ? "module" : "documentation") . " found for \"$_\".\n";
921 0 0         if ( @{ $self->{'found'} } ) {
  0            
922 0           print STDERR "However, try\n";
923 0           my $me = $self->program_name;
924 0           for my $dir (@{ $self->{'found'} }) {
  0            
925 0 0         opendir(DIR, $dir) or $self->die( "opendir $dir: $!" );
926 0           while (my $file = readdir(DIR)) {
927 0 0         next if ($file =~ /^\./s);
928 0           $file =~ s/\.(pm|pod)\z//; # XXX: badfs
929 0           print STDERR "\t$me $_\::$file\n";
930             }
931 0 0         closedir(DIR) or $self->die( "closedir $dir: $!" );
932             }
933             }
934             }
935             }
936 0           push(@found,@files);
937             }
938 0           return @found;
939             }
940              
941             #..........................................................................
942              
943             sub maybe_generate_dynamic_pod {
944 0     0 0   my($self, $found_things) = @_;
945 0           my @dynamic_pod;
946              
947 0 0         $self->search_perlapi($found_things, \@dynamic_pod) if $self->opt_a;
948              
949 0 0         $self->search_perlfunc($found_things, \@dynamic_pod) if $self->opt_f;
950              
951 0 0         $self->search_perlvar($found_things, \@dynamic_pod) if $self->opt_v;
952              
953 0 0         $self->search_perlfaqs($found_things, \@dynamic_pod) if $self->opt_q;
954              
955 0 0 0       if( ! $self->opt_f and ! $self->opt_q and ! $self->opt_v and ! $self->opt_a) {
    0          
956 0           DEBUG > 4 and print "That's a non-dynamic pod search.\n";
957             } elsif ( @dynamic_pod ) {
958 0           $self->aside("Hm, I found some Pod from that search!\n");
959 0           my ($buffd, $buffer) = $self->new_tempfile('pod', 'dyn');
960 0 0 0       if ( $] >= 5.008 && $self->opt_L ) {
961 0           binmode($buffd, ":encoding(UTF-8)");
962 0           print $buffd "=encoding utf8\n\n";
963             }
964              
965 0           push @{ $self->{'temp_file_list'} }, $buffer;
  0            
966             # I.e., it MIGHT be deleted at the end.
967              
968 0   0       my $in_list = !$self->not_dynamic && $self->opt_f || $self->opt_v || $self->opt_a;
969              
970 0 0         print $buffd "=over 8\n\n" if $in_list;
971 0 0         print $buffd @dynamic_pod or $self->die( "Can't print $buffer: $!" );
972 0 0         print $buffd "=back\n" if $in_list;
973              
974 0 0         close $buffd or $self->die( "Can't close $buffer: $!" );
975              
976 0           @$found_things = $buffer;
977             # Yes, so found_things never has more than one thing in
978             # it, by time we leave here
979              
980 0           $self->add_formatter_option('__filter_nroff' => 1);
981              
982             } else {
983 0           @$found_things = ();
984 0           $self->aside("I found no Pod from that search!\n");
985             }
986              
987 0           return;
988             }
989              
990             #..........................................................................
991              
992             sub not_dynamic {
993 0     0 0   my ($self,$value) = @_;
994 0 0         $self->{__not_dynamic} = $value if @_ == 2;
995 0           return $self->{__not_dynamic};
996             }
997              
998             #..........................................................................
999              
1000             sub add_formatter_option { # $self->add_formatter_option('key' => 'value');
1001 0     0 0   my $self = shift;
1002 0 0         push @{ $self->{'formatter_switches'} }, [ @_ ] if @_;
  0            
1003              
1004             DEBUG > 3 and printf "Formatter switches now: [%s]\n",
1005 0           join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
1006              
1007 0           return;
1008             }
1009              
1010             #.........................................................................
1011              
1012             sub new_translator { # $tr = $self->new_translator($lang);
1013 0     0 0   my $self = shift;
1014 0           my $lang = shift;
1015              
1016 0           local @INC = @INC;
1017 0 0         pop @INC if $INC[-1] eq '.';
1018 0           my $pack = 'POD2::' . uc($lang);
1019 0           eval "require $pack";
1020 0 0 0       if ( !$@ && $pack->can('new') ) {
1021 0           return $pack->new();
1022             }
1023              
1024 0           eval { require POD2::Base };
  0            
1025 0 0         return if $@;
1026              
1027 0           return POD2::Base->new({ lang => $lang });
1028             }
1029              
1030             #.........................................................................
1031              
1032             sub add_translator { # $self->add_translator($lang);
1033 0     0 0   my $self = shift;
1034 0           for my $lang (@_) {
1035 0           my $tr = $self->new_translator($lang);
1036 0 0         if ( defined $tr ) {
1037 0           push @{ $self->{'translators'} }, $tr;
  0            
1038 0           push @{ $self->{'extra_search_dirs'} }, $tr->pod_dirs;
  0            
1039              
1040 0           $self->aside( "translator for '$lang' loaded\n" );
1041             } else {
1042             # non-installed or bad translator package
1043 0           $self->warn( "Perldoc cannot load translator package for '$lang': ignored\n" );
1044             }
1045              
1046             }
1047 0           return;
1048             }
1049              
1050             #..........................................................................
1051              
1052             sub open_fh {
1053 0     0 0   my ($self, $op, $path) = @_;
1054              
1055 0 0         open my $fh, $op, $path or $self->die("Couldn't open $path: $!");
1056 0           return $fh;
1057             }
1058              
1059             sub set_encoding {
1060 0     0 0   my ($self, $fh, $encoding) = @_;
1061              
1062 0 0         if ( $encoding =~ /utf-?8/i ) {
1063 0           $encoding = ":encoding(UTF-8)";
1064             }
1065             else {
1066 0           $encoding = ":encoding($encoding)";
1067             }
1068              
1069 0 0         if ( $] < 5.008 ) {
1070 0           $self->aside("Your old perl doesn't have proper unicode support.");
1071             }
1072             else {
1073 0           binmode($fh, $encoding);
1074             }
1075              
1076 0           return $fh;
1077             }
1078              
1079             sub search_perlvar {
1080 0     0 0   my($self, $found_things, $pod) = @_;
1081              
1082 0           my $opt = $self->opt_v;
1083              
1084 0 0         if ( $opt !~ /^ (?: [\@\%\$]\S+ | [A-Z]\w* ) $/x ) {
1085 0           CORE::die( "'$opt' does not look like a Perl variable\n" );
1086             }
1087              
1088 0           DEBUG > 2 and print "Search: @$found_things\n";
1089              
1090 0           my $perlvar = shift @$found_things;
1091 0           my $fh = $self->open_fh("<", $perlvar);
1092              
1093 0 0 0       if ( $opt ne '$0' && $opt =~ /^\$\d+$/ ) { # handle $1, $2, ...
1094 0           $opt = '$>';
1095             }
1096 0           my $search_re = quotemeta($opt);
1097              
1098 0           DEBUG > 2 and
1099             print "Going to perlvar-scan for $search_re in $perlvar\n";
1100              
1101             # Skip introduction
1102 0           local $_;
1103 0           my $enc;
1104 0           while (<$fh>) {
1105 0 0         $enc = $1 if /^=encoding\s+(\S+)/;
1106 0 0         last if /^=over 8/;
1107             }
1108              
1109 0 0         $fh = $self->set_encoding($fh, $enc) if $enc;
1110              
1111             # Look for our variable
1112 0           my $found = 0;
1113 0           my $inheader = 1;
1114 0           my $inlist = 0;
1115 0           while (<$fh>) {
1116 0 0         last if /^=head2 Error Indicators/;
1117             # \b at the end of $` and friends borks things!
1118 0 0         if ( m/^=item\s+$search_re\s/ ) {
    0          
    0          
1119 0           $found = 1;
1120             }
1121             elsif (/^=item/) {
1122 0 0 0       last if $found && !$inheader && !$inlist;
      0        
1123             }
1124             elsif (!/^\s+$/) { # not a blank line
1125 0 0         if ( $found ) {
1126 0           $inheader = 0; # don't accept more =item (unless inlist)
1127             }
1128             else {
1129 0           @$pod = (); # reset
1130 0           $inheader = 1; # start over
1131 0           next;
1132             }
1133             }
1134              
1135 0 0         if (/^=over/) {
    0          
1136 0           ++$inlist;
1137             }
1138             elsif (/^=back/) {
1139 0 0 0       last if $found && !$inheader && !$inlist;
      0        
1140 0           --$inlist;
1141             }
1142 0           push @$pod, $_;
1143             # ++$found if /^\w/; # found descriptive text
1144             }
1145 0 0         @$pod = () unless $found;
1146 0 0         if (!@$pod) {
1147 0           CORE::die( "No documentation for perl variable '$opt' found\n" );
1148             }
1149 0 0         close $fh or $self->die( "Can't close $perlvar: $!" );
1150              
1151 0           return;
1152             }
1153              
1154             #..........................................................................
1155              
1156             sub search_perlop {
1157 0     0 0   my ($self,$found_things,$pod) = @_;
1158              
1159 0           $self->not_dynamic( 1 );
1160              
1161 0           my $perlop = shift @$found_things;
1162             # XXX FIXME: getting filehandles should probably be done in a single place
1163             # especially since we need to support UTF8 or other encoding when dealing
1164             # with perlop, perlfunc, perlapi, perlfaq[1-9]
1165 0           my $fh = $self->open_fh('<', $perlop);
1166              
1167 0           my $thing = $self->opt_f;
1168              
1169 0           my $previous_line;
1170 0           my $push = 0;
1171 0           my $seen_item = 0;
1172 0           my $skip = 1;
1173              
1174 0           while( my $line = <$fh> ) {
1175 0 0         $line =~ /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1176             # only start search after we hit the operator section
1177 0 0         if ($line =~ m!^X!) {
1178 0           $skip = 0;
1179             }
1180              
1181 0 0         next if $skip;
1182              
1183             # strategy is to capture the previous line until we get a match on X<$thingy>
1184             # if the current line contains X<$thingy>, then we push "=over", the previous line,
1185             # the current line and keep pushing current line until we see a ^X,
1186             # then we chop off final line from @$pod and add =back
1187             #
1188             # At that point, Bob's your uncle.
1189              
1190 0 0 0       if ( $line =~ m!X<+\s*\Q$thing\E\s*>+!) {
    0 0        
    0 0        
    0          
1191 0 0         if ( $previous_line ) {
1192 0           push @$pod, "=over 8\n\n", $previous_line;
1193 0           $previous_line = "";
1194             }
1195 0           push @$pod, $line;
1196 0           $push = 1;
1197              
1198             }
1199             elsif ( $push and $line =~ m!^=item\s*.*$! ) {
1200 0           $seen_item = 1;
1201             }
1202             elsif ( $push and $seen_item and $line =~ m!^X<+\s*[ a-z,?-]+\s*>+!) {
1203 0           $push = 0;
1204 0           $seen_item = 0;
1205 0           last;
1206             }
1207             elsif ( $push ) {
1208 0           push @$pod, $line;
1209             }
1210              
1211             else {
1212 0           $previous_line = $line;
1213             }
1214              
1215             } #end while
1216              
1217             # we overfilled by 1 line, so pop off final array element if we have any
1218 0 0         if ( scalar @$pod ) {
1219 0           pop @$pod;
1220              
1221             # and add the =back
1222 0           push @$pod, "\n\n=back\n";
1223 0           DEBUG > 8 and print "PERLOP POD --->" . (join "", @$pod) . "<---\n";
1224             }
1225             else {
1226 0           DEBUG > 4 and print "No pod from perlop\n";
1227             }
1228              
1229 0           close $fh;
1230              
1231 0           return;
1232             }
1233              
1234             #..........................................................................
1235              
1236             sub search_perlapi {
1237 0     0 0   my($self, $found_things, $pod) = @_;
1238              
1239 0           DEBUG > 2 and print "Search: @$found_things\n";
1240              
1241 0           my $perlapi = shift @$found_things;
1242 0           my $fh = $self->open_fh('<', $perlapi);
1243              
1244 0           my $search_re = quotemeta($self->opt_a);
1245              
1246 0           DEBUG > 2 and
1247             print "Going to perlapi-scan for $search_re in $perlapi\n";
1248              
1249 0           local $_;
1250              
1251             # Look for our function
1252 0           my $found = 0;
1253 0           my $inlist = 0;
1254              
1255 0           my @related;
1256             my $related_re;
1257 0           while (<$fh>) {
1258 0 0         /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1259              
1260 0 0 0       if ( m/^=item\s+$search_re\b/ ) {
    0 0        
    0          
    0          
1261 0           $found = 1;
1262             }
1263             elsif (@related > 1 and /^=item/) {
1264 0   0       $related_re ||= join "|", @related;
1265 0 0         if (m/^=item\s+(?:$related_re)\b/) {
1266 0           $found = 1;
1267             }
1268             else {
1269 0           last;
1270             }
1271             }
1272             elsif (/^=item/) {
1273 0 0 0       last if $found > 1 and not $inlist;
1274             }
1275             elsif ($found and /^X<[^>]+>/) {
1276 0           push @related, m/X<([^>]+)>/g;
1277             }
1278 0 0         next unless $found;
1279 0 0         if (/^=over/) {
    0          
1280 0           ++$inlist;
1281             }
1282             elsif (/^=back/) {
1283 0 0 0       last if $found > 1 and not $inlist;
1284 0           --$inlist;
1285             }
1286 0           push @$pod, $_;
1287 0 0         ++$found if /^\w/; # found descriptive text
1288             }
1289              
1290 0 0         if (!@$pod) {
1291 0           CORE::die( sprintf
1292             "No documentation for perl api function '%s' found\n",
1293             $self->opt_a )
1294             ;
1295             }
1296 0 0         close $fh or $self->die( "Can't open $perlapi: $!" );
1297              
1298 0           return;
1299             }
1300              
1301             #..........................................................................
1302              
1303             sub search_perlfunc {
1304 0     0 0   my($self, $found_things, $pod) = @_;
1305              
1306 0           DEBUG > 2 and print "Search: @$found_things\n";
1307              
1308 0           my $pfunc = shift @$found_things;
1309 0           my $fh = $self->open_fh("<", $pfunc); # "Funk is its own reward"
1310              
1311             # Functions like -r, -e, etc. are listed under `-X'.
1312 0 0         my $search_re = ($self->opt_f =~ /^-[rwxoRWXOeszfdlpSbctugkTBMAC]$/)
1313             ? '(?:I<)?-X' : quotemeta($self->opt_f) ;
1314              
1315 0           DEBUG > 2 and
1316             print "Going to perlfunc-scan for $search_re in $pfunc\n";
1317              
1318 0           my $re = 'Alphabetical Listing of Perl Functions';
1319              
1320             # Check available translator or backup to default (english)
1321 0 0 0       if ( $self->opt_L && defined $self->{'translators'}->[0] ) {
1322 0           my $tr = $self->{'translators'}->[0];
1323 0 0         $re = $tr->search_perlfunc_re if $tr->can('search_perlfunc_re');
1324 0 0         if ( $] < 5.008 ) {
1325 0           $self->aside("Your old perl doesn't really have proper unicode support.");
1326             }
1327             }
1328              
1329             # Skip introduction
1330 0           local $_;
1331 0           while (<$fh>) {
1332 0 0         /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1333 0 0         last if /^=head2 (?:$re|Alphabetical Listing of Perl Functions)/;
1334             }
1335              
1336             # Look for our function
1337 0           my $found = 0;
1338 0           my $inlist = 0;
1339              
1340 0           my @perlops = qw(m q qq qr qx qw s tr y);
1341              
1342 0           my @related;
1343             my $related_re;
1344 0           while (<$fh>) { # "The Mothership Connection is here!"
1345 0 0         last if( grep{ $self->opt_f eq $_ }@perlops );
  0            
1346              
1347 0 0 0       if ( /^=over/ and not $found ) {
    0 0        
      0        
1348 0           ++$inlist;
1349             }
1350             elsif ( /^=back/ and not $found and $inlist ) {
1351 0           --$inlist;
1352             }
1353              
1354              
1355 0 0 0       if ( m/^=item\s+$search_re\b/ and $inlist < 2 ) {
    0 0        
    0 0        
    0          
1356 0           $found = 1;
1357             }
1358             elsif (@related > 1 and /^=item/) {
1359 0   0       $related_re ||= join "|", @related;
1360 0 0         if (m/^=item\s+(?:$related_re)\b/) {
1361 0           $found = 1;
1362             }
1363             else {
1364 0 0 0       last if $found > 1 and $inlist < 2;
1365             }
1366             }
1367             elsif (/^=item|^=back/) {
1368 0 0 0       last if $found > 1 and $inlist < 2;
1369             }
1370             elsif ($found and /^X<[^>]+>/) {
1371 0           push @related, m/X<([^>]+)>/g;
1372             }
1373 0 0         next unless $found;
1374 0 0         if (/^=over/) {
    0          
1375 0           ++$inlist;
1376             }
1377             elsif (/^=back/) {
1378 0           --$inlist;
1379             }
1380 0           push @$pod, $_;
1381 0 0         ++$found if /^\w/; # found descriptive text
1382             }
1383              
1384 0 0         if( !@$pod ){
1385 0           $self->search_perlop( $found_things, $pod );
1386             }
1387              
1388 0 0         if (!@$pod) {
1389 0           CORE::die( sprintf
1390             "No documentation for perl function '%s' found\n",
1391             $self->opt_f )
1392             ;
1393             }
1394 0 0         close $fh or $self->die( "Can't close $pfunc: $!" );
1395              
1396 0           return;
1397             }
1398              
1399             #..........................................................................
1400              
1401             sub search_perlfaqs {
1402 0     0 0   my( $self, $found_things, $pod) = @_;
1403              
1404 0           my $found = 0;
1405 0           my %found_in;
1406 0           my $search_key = $self->opt_q;
1407              
1408 0 0         my $rx = eval { qr/$search_key/ }
  0            
1409             or $self->die( <
1410             Invalid regular expression '$search_key' given as -q pattern:
1411             $@
1412             Did you mean \\Q$search_key ?
1413              
1414             EOD
1415              
1416 0           local $_;
1417 0           foreach my $file (@$found_things) {
1418 0 0         $self->die( "invalid file spec: $!" ) if $file =~ /[<>|]/;
1419 0           my $fh = $self->open_fh("<", $file);
1420 0           while (<$fh>) {
1421 0 0         /^=encoding\s+(\S+)/ && $self->set_encoding($fh, $1);
1422 0 0         if ( m/^=head2\s+.*(?:$search_key)/i ) {
    0          
1423 0           $found = 1;
1424 0 0         push @$pod, "=head1 Found in $file\n\n" unless $found_in{$file}++;
1425             }
1426             elsif (/^=head[12]/) {
1427 0           $found = 0;
1428             }
1429 0 0         next unless $found;
1430 0           push @$pod, $_;
1431             }
1432 0           close($fh);
1433             }
1434 0 0         CORE::die("No documentation for perl FAQ keyword '$search_key' found\n")
1435             unless @$pod;
1436              
1437 0 0         if ( $self->opt_l ) {
1438 0           CORE::die((join "\n", keys %found_in) . "\n");
1439             }
1440 0           return;
1441             }
1442              
1443              
1444             #..........................................................................
1445              
1446             sub render_findings {
1447             # Return the filename to open
1448              
1449 0     0 0   my($self, $found_things) = @_;
1450              
1451 0   0       my $formatter_class = $self->{'formatter_class'}
1452             || $self->die( "No formatter class set!?" );
1453 0 0         my $formatter = $formatter_class->can('new')
1454             ? $formatter_class->new
1455             : $formatter_class
1456             ;
1457              
1458 0 0         if(! @$found_things) {
    0          
1459 0           $self->die( "Nothing found?!" );
1460             # should have been caught before here
1461             } elsif(@$found_things > 1) {
1462 0           $self->warn(
1463             "Perldoc is only really meant for reading one document at a time.\n",
1464             "So these parameters are being ignored: ",
1465             join(' ', @$found_things[1 .. $#$found_things] ),
1466             "\n" );
1467             }
1468              
1469 0           my $file = $found_things->[0];
1470              
1471             DEBUG > 3 and printf "Formatter switches now: [%s]\n",
1472 0           join ' ', map "[@$_]", @{ $self->{'formatter_switches'} };
1473              
1474             # Set formatter options:
1475 0 0         if( ref $formatter ) {
1476 0 0         foreach my $f (@{ $self->{'formatter_switches'} || [] }) {
  0            
1477 0           my($switch, $value, $silent_fail) = @$f;
1478 0 0         if( $formatter->can($switch) ) {
1479 0 0         eval { $formatter->$switch( defined($value) ? $value : () ) };
  0            
1480 0 0         $self->warn( "Got an error when setting $formatter_class\->$switch:\n$@\n" )
1481             if $@;
1482             } else {
1483 0 0 0       if( $silent_fail or $switch =~ m/^__/s ) {
1484 0           DEBUG > 2 and print "Formatter $formatter_class doesn't support $switch\n";
1485             } else {
1486 0           $self->warn( "$formatter_class doesn't recognize the $switch switch.\n" );
1487             }
1488             }
1489             }
1490             }
1491              
1492 0   0       $self->{'output_is_binary'} =
1493             $formatter->can('write_with_binmode') && $formatter->write_with_binmode;
1494              
1495 0 0 0       if( $self->{podnames} and exists $self->{podnames}{$file} and
      0        
1496             $formatter->can('name') ) {
1497 0           $formatter->name($self->{podnames}{$file});
1498             }
1499              
1500 0   0       my ($out_fh, $out) = $self->new_output_file(
1501             ( $formatter->can('output_extension') && $formatter->output_extension )
1502             || undef,
1503             $self->useful_filename_bit,
1504             );
1505              
1506             # Now, finally, do the formatting!
1507             {
1508 0           local $^W = $^W;
  0            
1509 0 0         if(DEBUG() or $self->opt_D) {
1510             # feh, let 'em see it
1511             } else {
1512 0           $^W = 0;
1513             # The average user just has no reason to be seeing
1514             # $^W-suppressible warnings from the formatting!
1515             }
1516              
1517 0           eval { $formatter->parse_from_file( $file, $out_fh ) };
  0            
1518             }
1519              
1520 0 0         $self->warn( "Error while formatting with $formatter_class:\n $@\n" ) if $@;
1521 0           DEBUG > 2 and print "Back from formatting with $formatter_class\n";
1522              
1523 0 0         close $out_fh
1524             or $self->warn( "Can't close $out: $!\n(Did $formatter already close it?)" );
1525 0           sleep 0; sleep 0; sleep 0;
  0            
  0            
1526             # Give the system a few timeslices to meditate on the fact
1527             # that the output file does in fact exist and is closed.
1528              
1529 0           $self->unlink_if_temp_file($file);
1530              
1531 0 0         unless( -s $out ) {
1532 0 0         if( $formatter->can( 'if_zero_length' ) ) {
1533             # Basically this is just a hook for Pod::Simple::Checker; since
1534             # what other class could /happily/ format an input file with Pod
1535             # as a 0-length output file?
1536 0           $formatter->if_zero_length( $file, $out, $out_fh );
1537             } else {
1538 0           $self->warn( "Got a 0-length file from $$found_things[0] via $formatter_class!?\n" );
1539             }
1540             }
1541              
1542 0           DEBUG and print "Finished writing to $out.\n";
1543 0 0         return($out, $formatter) if wantarray;
1544 0           return $out;
1545             }
1546              
1547             #..........................................................................
1548              
1549             sub unlink_if_temp_file {
1550             # Unlink the specified file IFF it's in the list of temp files.
1551             # Really only used in the case of -f / -q things when we can
1552             # throw away the dynamically generated source pod file once
1553             # we've formatted it.
1554             #
1555 0     0 0   my($self, $file) = @_;
1556 0 0 0       return unless defined $file and length $file;
1557              
1558 0   0       my $temp_file_list = $self->{'temp_file_list'} || return;
1559 0 0         if(grep $_ eq $file, @$temp_file_list) {
1560 0           $self->aside("Unlinking $file\n");
1561 0 0         unlink($file) or $self->warn( "Odd, couldn't unlink $file: $!" );
1562             } else {
1563 0           DEBUG > 1 and print "$file isn't a temp file, so not unlinking.\n";
1564             }
1565 0           return;
1566             }
1567              
1568             #..........................................................................
1569              
1570              
1571             sub after_rendering {
1572 0     0 0   my $self = $_[0];
1573 0 0         $self->after_rendering_VMS if $self->is_vms;
1574 0 0         $self->after_rendering_MSWin32 if $self->is_mswin32;
1575 0 0         $self->after_rendering_Dos if $self->is_dos;
1576 0 0         $self->after_rendering_OS2 if $self->is_os2;
1577 0           return;
1578             }
1579              
1580 0     0 0   sub after_rendering_VMS { return }
1581 0     0 0   sub after_rendering_Dos { return }
1582 0     0 0   sub after_rendering_OS2 { return }
1583 0     0 0   sub after_rendering_MSWin32 { return }
1584              
1585             #..........................................................................
1586             # : : : : : : : : :
1587             #..........................................................................
1588              
1589             sub minus_f_nocase { # i.e., do like -f, but without regard to case
1590              
1591 0     0 0   my($self, $dir, $file) = @_;
1592 0           my $path = catfile($dir,$file);
1593 0 0 0       return $path if -f $path and -r _;
1594              
1595 0 0 0       if(!$self->opt_i
      0        
      0        
      0        
1596             or $self->is_vms or $self->is_mswin32
1597             or $self->is_dos or $self->is_os2
1598             ) {
1599             # On a case-forgiving file system, or if case is important,
1600             # that is it, all we can do.
1601 0 0         $self->warn( "Ignored $path: unreadable\n" ) if -f _;
1602 0           return '';
1603             }
1604              
1605 0           local *DIR;
1606 0           my @p = ($dir);
1607 0           my($p,$cip);
1608 0           foreach $p (splitdir $file){
1609 0           my $try = catfile @p, $p;
1610 0           $self->aside("Scrutinizing $try...\n");
1611 0           stat $try;
1612 0 0 0       if (-d _) {
    0 0        
    0          
    0          
1613 0           push @p, $p;
1614 0 0         if ( $p eq $self->{'target'} ) {
1615 0           my $tmp_path = catfile @p;
1616 0           my $path_f = 0;
1617 0           for (@{ $self->{'found'} }) {
  0            
1618 0 0         $path_f = 1 if $_ eq $tmp_path;
1619             }
1620 0 0         push (@{ $self->{'found'} }, $tmp_path) unless $path_f;
  0            
1621 0           $self->aside( "Found as $tmp_path but directory\n" );
1622             }
1623             }
1624             elsif (-f _ && -r _ && lc($try) eq lc($path)) {
1625 0           return $try;
1626             }
1627             elsif (-f _) {
1628 0           $self->warn( "Ignored $try: unreadable or file/dir mismatch\n" );
1629             }
1630             elsif (-d catdir(@p)) { # at least we see the containing directory!
1631 0           my $found = 0;
1632 0           my $lcp = lc $p;
1633 0           my $p_dirspec = catdir(@p);
1634 0 0         opendir DIR, $p_dirspec or $self->die( "opendir $p_dirspec: $!" );
1635 0           while(defined( $cip = readdir(DIR) )) {
1636 0 0         if (lc $cip eq $lcp){
1637 0           $found++;
1638 0           last; # XXX stop at the first? what if there's others?
1639             }
1640             }
1641 0 0         closedir DIR or $self->die( "closedir $p_dirspec: $!" );
1642 0 0         return "" unless $found;
1643              
1644 0           push @p, $cip;
1645 0           my $p_filespec = catfile(@p);
1646 0 0 0       return $p_filespec if -f $p_filespec and -r _;
1647 0 0         $self->warn( "Ignored $p_filespec: unreadable\n" ) if -f _;
1648             }
1649             }
1650 0           return "";
1651             }
1652              
1653             #..........................................................................
1654              
1655             sub pagers_guessing {
1656             # TODO: This whole subroutine needs to be rewritten. It's semi-insane
1657             # right now.
1658              
1659 0     0 0   my $self = shift;
1660              
1661 0           my @pagers;
1662 0           push @pagers, $self->pagers;
1663 0           $self->{'pagers'} = \@pagers;
1664              
1665 0 0         if ($self->is_mswin32) {
    0          
    0          
    0          
1666 0           push @pagers, qw( more< less notepad );
1667 0 0         unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
1668             }
1669             elsif ($self->is_vms) {
1670 0           push @pagers, qw( most more less type/page );
1671             }
1672             elsif ($self->is_dos) {
1673 0           push @pagers, qw( less.exe more.com< );
1674 0 0         unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
1675             }
1676             elsif ( $self->is_amigaos) {
1677 0           push @pagers, qw( /SYS/Utilities/MultiView /SYS/Utilities/More /C/TYPE );
1678 0 0         unshift @pagers, "$ENV{PAGER}" if $ENV{PAGER};
1679             }
1680             else {
1681 0 0         if ($self->is_os2) {
1682 0           unshift @pagers, 'less', 'cmd /c more <';
1683             }
1684 0           push @pagers, qw( more less pg view cat );
1685 0 0         unshift @pagers, "$ENV{PAGER} <" if $ENV{PAGER};
1686             }
1687              
1688 0 0         if ($self->is_cygwin) {
1689 0 0 0       if (($pagers[0] eq 'less') || ($pagers[0] eq '/usr/bin/less')) {
1690 0           unshift @pagers, '/usr/bin/less -isrR';
1691 0 0         unshift @pagers, $ENV{PAGER} if $ENV{PAGER};
1692             }
1693             }
1694              
1695 0 0         if ( $self->opt_m ) {
1696             unshift @pagers, "$ENV{PERLDOC_SRC_PAGER}" if $ENV{PERLDOC_SRC_PAGER}
1697 0 0         }
1698             else {
1699 0 0         unshift @pagers, "$ENV{MANPAGER} <" if $ENV{MANPAGER};
1700 0 0         unshift @pagers, "$ENV{PERLDOC_PAGER} <" if $ENV{PERLDOC_PAGER};
1701             }
1702              
1703 0           $self->aside("Pagers: ", (join ", ", @pagers));
1704              
1705 0           return;
1706             }
1707              
1708             #..........................................................................
1709              
1710             sub page_module_file {
1711 0     0 0   my($self, @found) = @_;
1712              
1713             # Security note:
1714             # Don't ever just pass this off to anything like MSWin's "start.exe",
1715             # since we might be calling on a .pl file, and we wouldn't want that
1716             # to actually /execute/ the file that we just want to page thru!
1717             # Also a consideration if one were to use a web browser as a pager;
1718             # doing so could trigger the browser's MIME mapping for whatever
1719             # it thinks .pm/.pl/whatever is. Probably just a (useless and
1720             # annoying) "Save as..." dialog, but potentially executing the file
1721             # in question -- particularly in the case of MSIE and it's, ahem,
1722             # occasionally hazy distinction between OS-local extension
1723             # associations, and browser-specific MIME mappings.
1724              
1725 0 0         if(@found > 1) {
1726 0           $self->warn(
1727             "Perldoc is only really meant for reading one document at a time.\n" .
1728             "So these files are being ignored: " .
1729             join(' ', @found[1 .. $#found] ) .
1730             "\n" )
1731             }
1732              
1733 0           return $self->page($found[0], $self->{'output_to_stdout'}, $self->pagers);
1734              
1735             }
1736              
1737             #..........................................................................
1738              
1739             sub check_file {
1740 0     0 0   my($self, $dir, $file) = @_;
1741              
1742 0 0         unless( ref $self ) {
1743             # Should never get called:
1744 0           $Carp::Verbose = 1;
1745 0           require Carp;
1746 0           Carp::croak( join '',
1747             "Crazy ", __PACKAGE__, " error:\n",
1748             "check_file must be an object_method!\n",
1749             "Aborting"
1750             );
1751             }
1752              
1753 0 0 0       if(length $dir and not -d $dir) {
1754 0           DEBUG > 3 and print " No dir $dir -- skipping.\n";
1755 0           return "";
1756             }
1757              
1758 0           my $path = $self->minus_f_nocase($dir,$file);
1759 0 0 0       if( length $path and ($self->opt_m ? $self->isprintable($path)
    0          
1760             : $self->containspod($path)) ) {
1761 0           DEBUG > 3 and print
1762             " The file $path indeed looks promising!\n";
1763 0           return $path;
1764             }
1765 0           DEBUG > 3 and print " No good: $file in $dir\n";
1766              
1767 0           return "";
1768             }
1769              
1770             sub isprintable {
1771 0     0 0   my($self, $file, $readit) = @_;
1772 0           my $size= 1024;
1773 0           my $maxunprintfrac= 0.2; # tolerate some unprintables for UTF-8 comments etc.
1774              
1775 0 0 0       return 1 if !$readit && $file =~ /\.(?:pl|pm|pod|cmd|com|bat)\z/i;
1776              
1777 0           my $data;
1778 0           local($_);
1779 0           my $fh = $self->open_fh("<", $file);
1780 0           read $fh, $data, $size;
1781 0           close $fh;
1782 0           $size= length($data);
1783 0           $data =~ tr/\x09-\x0D\x20-\x7E//d;
1784 0           return length($data) <= $size*$maxunprintfrac;
1785             }
1786              
1787             #..........................................................................
1788              
1789             sub containspod {
1790 0     0 0   my($self, $file, $readit) = @_;
1791 0 0 0       return 1 if !$readit && $file =~ /\.pod\z/i;
1792              
1793              
1794             # Under cygwin the /usr/bin/perl is legal executable, but
1795             # you cannot open a file with that name. It must be spelled
1796             # out as "/usr/bin/perl.exe".
1797             #
1798             # The following if-case under cygwin prevents error
1799             #
1800             # $ perldoc perl
1801             # Cannot open /usr/bin/perl: no such file or directory
1802             #
1803             # This would work though
1804             #
1805             # $ perldoc perl.pod
1806              
1807 0 0 0       if ( $self->is_cygwin and -x $file and -f "$file.exe" )
      0        
1808             {
1809 0 0         $self->warn( "Cygwin $file.exe search skipped\n" ) if DEBUG or $self->opt_D;
1810 0           return 0;
1811             }
1812              
1813 0           local($_);
1814 0           my $fh = $self->open_fh("<", $file);
1815 0           while (<$fh>) {
1816 0 0         if (/^=head/) {
1817 0 0         close($fh) or $self->die( "Can't close $file: $!" );
1818 0           return 1;
1819             }
1820             }
1821 0 0         close($fh) or $self->die( "Can't close $file: $!" );
1822 0           return 0;
1823             }
1824              
1825             #..........................................................................
1826              
1827             sub maybe_extend_searchpath {
1828 0     0 0   my $self = shift;
1829              
1830             # Does this look like a module or extension directory?
1831              
1832 0 0 0       if (-f "Makefile.PL" || -f "Build.PL") {
1833              
1834 0           push @{$self->{search_path} }, '.','lib';
  0            
1835              
1836             # don't add if superuser
1837 0 0 0       if ($< && $> && -d "blib") { # don't be looking too hard now!
      0        
1838 0           push @{ $self->{search_path} }, 'blib';
  0            
1839 0 0 0       $self->warn( $@ ) if $@ && $self->opt_D;
1840             }
1841             }
1842              
1843 0           return;
1844             }
1845              
1846             #..........................................................................
1847              
1848             sub new_output_file {
1849 0     0 0   my $self = shift;
1850 0           my $outspec = $self->opt_d; # Yes, -d overrides all else!
1851             # So don't call this twice per format-job!
1852              
1853 0 0 0       return $self->new_tempfile(@_) unless defined $outspec and length $outspec;
1854              
1855             # Otherwise open a write-handle on opt_d!f
1856              
1857 0           DEBUG > 3 and print "About to try writing to specified output file $outspec\n";
1858 0           my $fh = $self->open_fh(">", $outspec);
1859              
1860 0           DEBUG > 3 and print "Successfully opened $outspec\n";
1861 0 0         binmode($fh) if $self->{'output_is_binary'};
1862 0           return($fh, $outspec);
1863             }
1864              
1865             #..........................................................................
1866              
1867             sub useful_filename_bit {
1868             # This tries to provide a meaningful bit of text to do with the query,
1869             # such as can be used in naming the file -- since if we're going to be
1870             # opening windows on temp files (as a "pager" may well do!) then it's
1871             # better if the temp file's name (which may well be used as the window
1872             # title) isn't ALL just random garbage!
1873             # In other words "perldoc_LWPSimple_2371981429" is a better temp file
1874             # name than "perldoc_2371981429". So this routine is what tries to
1875             # provide the "LWPSimple" bit.
1876             #
1877 0     0 0   my $self = shift;
1878 0   0       my $pages = $self->{'pages'} || return undef;
1879 0 0         return undef unless @$pages;
1880              
1881 0           my $chunk = $pages->[0];
1882 0 0         return undef unless defined $chunk;
1883 0           $chunk =~ s/:://g;
1884 0           $chunk =~ s/\.\w+$//g; # strip any extension
1885 0 0         if( $chunk =~ m/([^\#\\:\/\$]+)$/s ) { # get basename, if it's a file
1886 0           $chunk = $1;
1887             } else {
1888 0           return undef;
1889             }
1890 0           $chunk =~ s/[^a-zA-Z0-9]+//g; # leave ONLY a-zA-Z0-9 things!
1891 0 0         $chunk = substr($chunk, -10) if length($chunk) > 10;
1892 0           return $chunk;
1893             }
1894              
1895             #..........................................................................
1896              
1897             sub new_tempfile { # $self->new_tempfile( [$suffix, [$infix] ] )
1898 0     0 0   my $self = shift;
1899              
1900 0           ++$Temp_Files_Created;
1901              
1902 0           require File::Temp;
1903 0           return File::Temp::tempfile(UNLINK => 1);
1904             }
1905              
1906             #..........................................................................
1907              
1908             sub page { # apply a pager to the output file
1909 0     0 0   my ($self, $output, $output_to_stdout, @pagers) = @_;
1910 0 0         if ($output_to_stdout) {
1911 0           $self->aside("Sending unpaged output to STDOUT.\n");
1912 0           my $fh = $self->open_fh("<", $output);
1913 0           local $_;
1914 0           while (<$fh>) {
1915 0 0         print or $self->die( "Can't print to stdout: $!" );
1916             }
1917 0 0         close $fh or $self->die( "Can't close while $output: $!" );
1918 0           $self->unlink_if_temp_file($output);
1919             } else {
1920             # On VMS, quoting prevents logical expansion, and temp files with no
1921             # extension get the wrong default extension (such as .LIS for TYPE)
1922              
1923 0 0         $output = VMS::Filespec::rmsexpand($output, '.') if $self->is_vms;
1924              
1925 0 0 0       $output =~ s{/}{\\}g if $self->is_mswin32 || $self->is_dos;
1926             # Altho "/" under MSWin is in theory good as a pathsep,
1927             # many many corners of the OS don't like it. So we
1928             # have to force it to be "\" to make everyone happy.
1929              
1930             # if we are on an amiga convert unix path to an amiga one
1931 0 0         $output =~ s/^\/(.*)\/(.*)/$1:$2/ if $self->is_amigaos;
1932              
1933 0           foreach my $pager (@pagers) {
1934 0           $self->aside("About to try calling $pager $output\n");
1935 0 0         if ($self->is_vms) {
    0          
1936 0 0         last if system("$pager $output") == 0;
1937             } elsif($self->is_amigaos) {
1938 0 0         last if system($pager, $output) == 0;
1939             } else {
1940 0           my $formatter = $self->{'formatter_class'};
1941 0 0         if ( $formatter->can('pager_configuration') ) {
1942 0           $self->aside("About to call $formatter" . "->pager_configuration(\"$pager\")\n");
1943 0           $formatter->pager_configuration($pager, $self);
1944             }
1945 0 0         last if system("$pager \"$output\"") == 0;
1946             }
1947             }
1948             }
1949 0           return;
1950             }
1951              
1952             #..........................................................................
1953              
1954             sub searchfor {
1955 0     0 0   my($self, $recurse,$s,@dirs) = @_;
1956 0           $s =~ s!::!/!g;
1957 0 0         $s = VMS::Filespec::unixify($s) if $self->is_vms;
1958 0 0 0       return $s if -f $s && $self->containspod($s);
1959 0           $self->aside( "Looking for $s in @dirs\n" );
1960 0           my $ret;
1961             my $i;
1962 0           my $dir;
1963 0           $self->{'target'} = (splitdir $s)[-1]; # XXX: why not use File::Basename?
1964 0           for ($i=0; $i<@dirs; $i++) {
1965 0           $dir = $dirs[$i];
1966 0 0         next unless -d $dir;
1967 0 0         ($dir = VMS::Filespec::unixpath($dir)) =~ s!/\z!! if $self->is_vms;
1968 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        
1969             or ( $ret = $self->check_file($dir,"$s.pm"))
1970             or ( $ret = $self->check_file($dir,$s))
1971             or ( $self->is_vms and
1972             $ret = $self->check_file($dir,"$s.com"))
1973             or ( $self->is_os2 and
1974             $ret = $self->check_file($dir,"$s.cmd"))
1975             or ( ($self->is_mswin32 or $self->is_dos or $self->is_os2) and
1976             $ret = $self->check_file($dir,"$s.bat"))
1977             or ( $ret = $self->check_file("$dir/pod","$s.pod"))
1978             or ( $ret = $self->check_file("$dir/pod",$s))
1979             or ( $ret = $self->check_file("$dir/pods","$s.pod"))
1980             or ( $ret = $self->check_file("$dir/pods",$s))
1981             ) {
1982 0           DEBUG > 1 and print " Found $ret\n";
1983 0           return $ret;
1984             }
1985              
1986 0 0         if ($recurse) {
1987 0 0         opendir(D,$dir) or $self->die( "Can't opendir $dir: $!" );
1988             my @newdirs = map catfile($dir, $_), grep {
1989 0 0 0       not /^\.\.?\z/s and
  0            
1990             not /^auto\z/s and # save time! don't search auto dirs
1991             -d catfile($dir, $_)
1992             } readdir D;
1993 0 0         closedir(D) or $self->die( "Can't closedir $dir: $!" );
1994 0 0         next unless @newdirs;
1995             # what a wicked map!
1996 0 0         @newdirs = map((s/\.dir\z//,$_)[1],@newdirs) if $self->is_vms;
1997 0           $self->aside( "Also looking in @newdirs\n" );
1998 0           push(@dirs,@newdirs);
1999             }
2000             }
2001 0           return ();
2002             }
2003              
2004             #..........................................................................
2005             {
2006             my $already_asserted;
2007             sub assert_closing_stdout {
2008 0     0 0   my $self = shift;
2009              
2010 0 0         return if $already_asserted;
2011              
2012 0           eval q~ END { close(STDOUT) || CORE::die "Can't close STDOUT: $!" } ~;
2013             # What for? to let the pager know that nothing more will come?
2014              
2015 0 0         $self->die( $@ ) if $@;
2016 0           $already_asserted = 1;
2017 0           return;
2018             }
2019             }
2020              
2021             #..........................................................................
2022              
2023             sub tweak_found_pathnames {
2024 0     0 0   my($self, $found) = @_;
2025 0 0         if ($self->is_mswin32) {
2026 0           foreach (@$found) { s,/,\\,g }
  0            
2027             }
2028 0           foreach (@$found) { s,',\\',g } # RT 37347
  0            
2029 0           return;
2030             }
2031              
2032             #..........................................................................
2033             # : : : : : : : : :
2034             #..........................................................................
2035              
2036             sub am_taint_checking {
2037 0     0 0   my $self = shift;
2038 0 0         $self->die( "NO ENVIRONMENT?!?!" ) unless keys %ENV; # reset iterator along the way
2039 0           my($k,$v) = each %ENV;
2040 0           return is_tainted($v);
2041             }
2042              
2043             #..........................................................................
2044              
2045             sub is_tainted { # just a function
2046 0     0 0   my $arg = shift;
2047 0           my $nada = substr($arg, 0, 0); # zero-length!
2048 0           local $@; # preserve the caller's version of $@
2049 0           eval { eval "# $nada" };
  0            
2050 0           return length($@) != 0;
2051             }
2052              
2053             #..........................................................................
2054              
2055             sub drop_privs_maybe {
2056 0     0 0   my $self = shift;
2057              
2058 0           DEBUG and print "Attempting to drop privs...\n";
2059              
2060             # Attempt to drop privs if we should be tainting and aren't
2061 0 0 0       if (!( $self->is_vms || $self->is_mswin32 || $self->is_dos
      0        
      0        
      0        
2062             || $self->is_os2
2063             )
2064             && ($> == 0 || $< == 0)
2065             && !$self->am_taint_checking()
2066             ) {
2067 0           my $id = eval { getpwnam("nobody") };
  0            
2068 0 0         $id = eval { getpwnam("nouser") } unless defined $id;
  0            
2069 0 0         $id = -2 unless defined $id;
2070             #
2071             # According to Stevens' APUE and various
2072             # (BSD, Solaris, HP-UX) man pages, setting
2073             # the real uid first and effective uid second
2074             # is the way to go if one wants to drop privileges,
2075             # because if one changes into an effective uid of
2076             # non-zero, one cannot change the real uid any more.
2077             #
2078             # Actually, it gets even messier. There is
2079             # a third uid, called the saved uid, and as
2080             # long as that is zero, one can get back to
2081             # uid of zero. Setting the real-effective *twice*
2082             # helps in *most* systems (FreeBSD and Solaris)
2083             # but apparently in HP-UX even this doesn't help:
2084             # the saved uid stays zero (apparently the only way
2085             # in HP-UX to change saved uid is to call setuid()
2086             # when the effective uid is zero).
2087             #
2088 0           eval {
2089 0           $< = $id; # real uid
2090 0           $> = $id; # effective uid
2091 0           $< = $id; # real uid
2092 0           $> = $id; # effective uid
2093             };
2094 0 0 0       if( !$@ && $< && $> ) {
    0 0        
2095 0           DEBUG and print "OK, I dropped privileges.\n";
2096             } elsif( $self->opt_U ) {
2097 0           DEBUG and print "Couldn't drop privileges, but in -U mode, so feh."
2098             } else {
2099 0           DEBUG and print "Hm, couldn't drop privileges. Ah well.\n";
2100             # We used to die here; but that seemed pointless.
2101             }
2102             }
2103 0           return;
2104             }
2105              
2106             #..........................................................................
2107              
2108             1;
2109              
2110             __END__