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