File Coverage

blib/lib/Pod/Usage.pm
Criterion Covered Total %
statement 145 194 74.7
branch 81 142 57.0
condition 30 67 44.7
subroutine 14 17 82.3
pod 1 8 12.5
total 271 428 63.3


line stmt bran cond sub pod time code
1             #############################################################################
2             # Pod/Usage.pm -- print usage messages for the running script.
3             #
4             # Copyright (c) 1996-2000 by Bradford Appleton. All rights reserved.
5             # Copyright (c) 2001-2016 by Marek Rouchal.
6             # This file is part of "Pod-Usage". Pod-Usage is free software;
7             # you can redistribute it and/or modify it under the same terms
8             # as Perl itself.
9             #############################################################################
10              
11             package Pod::Usage;
12 17     17   248013 use strict;
  17         221  
  17         459  
13              
14 17     17   221 use vars qw($VERSION @ISA @EXPORT);
  17         17  
  17         1581  
15             $VERSION = '1.69'; ## Current version of this package
16             require 5.006; ## requires this Perl version or later
17              
18             #use diagnostics;
19 17     17   68 use Carp;
  17         17  
  17         1105  
20 17     17   51 use Config;
  17         17  
  17         527  
21 17     17   51 use Exporter;
  17         0  
  17         476  
22 17     17   51 use File::Spec;
  17         17  
  17         935  
23              
24             @EXPORT = qw(&pod2usage);
25             BEGIN {
26 17   50 17   136 $Pod::Usage::Formatter ||= 'Pod::Text';
27 17         901 eval "require $Pod::Usage::Formatter";
28 17 50       573274 die $@ if $@;
29 17         31025 @ISA = ( $Pod::Usage::Formatter );
30             }
31              
32             our $MAX_HEADING_LEVEL = 3;
33              
34             ##---------------------------------------------------------------------------
35              
36             ##---------------------------------
37             ## Function definitions begin here
38             ##---------------------------------
39              
40             sub pod2usage {
41 15     15 0 32025310 local($_) = shift;
42 15         219 my %opts;
43             ## Collect arguments
44 15 100       509 if (@_ > 0) {
    100          
    50          
    50          
45             ## Too many arguments - assume that this is a hash and
46             ## the user forgot to pass a reference to it.
47 12         383 %opts = ($_, @_);
48             }
49             elsif (!defined $_) {
50 1         13 $_ = '';
51             }
52             elsif (ref $_) {
53             ## User passed a ref to a hash
54 0 0       0 %opts = %{$_} if (ref($_) eq 'HASH');
  0         0  
55             }
56             elsif (/^[-+]?\d+$/) {
57             ## User passed in the exit value to use
58 2         31 $opts{'-exitval'} = $_;
59             }
60             else {
61             ## User passed in a message to print before issuing usage.
62 0 0       0 $_ and $opts{'-message'} = $_;
63             }
64              
65             ## Need this for backward compatibility since we formerly used
66             ## options that were all uppercase words rather than ones that
67             ## looked like Unix command-line options.
68             ## to be uppercase keywords)
69             %opts = map {
70 15         295 my ($key, $val) = ($_, $opts{$_});
  38         263  
71 38         416 $key =~ s/^(?=\w)/-/;
72 38 50       703 $key =~ /^-msg/i and $key = '-message';
73 38 100       319 $key =~ /^-exit/i and $key = '-exitval';
74 38         250 lc($key) => $val;
75             } (keys %opts);
76              
77             ## Now determine default -exitval and -verbose values to use
78 15 100 100     522 if ((! defined $opts{'-exitval'}) && (! defined $opts{'-verbose'})) {
    100          
    100          
79 1         16 $opts{'-exitval'} = 2;
80 1         10 $opts{'-verbose'} = 0;
81             }
82             elsif (! defined $opts{'-exitval'}) {
83 2 50       16 $opts{'-exitval'} = ($opts{'-verbose'} > 0) ? 1 : 2;
84             }
85             elsif (! defined $opts{'-verbose'}) {
86             $opts{'-verbose'} = (lc($opts{'-exitval'}) eq 'noexit' ||
87 2   66     75 $opts{'-exitval'} < 2);
88             }
89              
90             ## Default the output file
91             $opts{'-output'} = (lc($opts{'-exitval'}) eq 'noexit' ||
92             $opts{'-exitval'} < 2) ? \*STDOUT : \*STDERR
93 15 100 100     590 unless (defined $opts{'-output'});
    50          
94             ## Default the input file
95 15 100       191 $opts{'-input'} = $0 unless (defined $opts{'-input'});
96              
97             ## Look up input file in path if it doesn't exist.
98 15 50 33     758 unless ((ref $opts{'-input'}) || (-e $opts{'-input'})) {
99 0         0 my $basename = $opts{'-input'};
100 0 0 0     0 my $pathsep = ($^O =~ /^(?:dos|os2|MSWin32)$/i) ? ';'
    0          
101             : (($^O eq 'MacOS' || $^O eq 'VMS') ? ',' : ':');
102 0   0     0 my $pathspec = $opts{'-pathlist'} || $ENV{PATH} || $ENV{PERL5LIB};
103              
104 0 0       0 my @paths = (ref $pathspec) ? @$pathspec : split($pathsep, $pathspec);
105 0         0 for my $dirname (@paths) {
106 0 0       0 $_ = File::Spec->catfile($dirname, $basename) if length;
107 0 0 0     0 last if (-e $_) && ($opts{'-input'} = $_);
108             }
109             }
110              
111             ## Now create a pod reader and constrain it to the desired sections.
112 15         216 my $parser = new Pod::Usage(USAGE_OPTIONS => \%opts);
113 15 100 66     201 if ($opts{'-verbose'} == 0) {
    100          
    100          
    50          
114 5         113 $parser->select('(?:SYNOPSIS|USAGE)\s*');
115             }
116             elsif ($opts{'-verbose'} == 1) {
117 4         121 my $opt_re = '(?i)' .
118             '(?:OPTIONS|ARGUMENTS)' .
119             '(?:\s*(?:AND|\/)\s*(?:OPTIONS|ARGUMENTS))?';
120 4         132 $parser->select( '(?:SYNOPSIS|USAGE)\s*', $opt_re, "DESCRIPTION/$opt_re" );
121             }
122             elsif ($opts{'-verbose'} >= 2 && $opts{'-verbose'} != 99) {
123 1         7 $parser->select('.*');
124             }
125             elsif ($opts{'-verbose'} == 99) {
126 5         54 my $sections = $opts{'-sections'};
127 5 100       236 $parser->select( (ref $sections) ? @$sections : $sections );
128 5         10 $opts{'-verbose'} = 1;
129             }
130              
131             ## Check for perldoc
132             my $progpath = $opts{'-perldoc'} ? $opts{'-perldoc'} :
133             File::Spec->catfile($Config{scriptdirexp}
134 15 50 33     3183 || $Config{scriptdir}, 'perldoc');
135              
136 15         293 my $version = sprintf("%vd",$^V);
137 15 50 33     769 if ($Config{versiononly} and $Config{startperl} =~ /\Q$version\E$/ ) {
138 0         0 $progpath .= $version;
139             }
140 15 50       480 $opts{'-noperldoc'} = 1 unless -e $progpath;
141              
142             ## Now translate the pod document and then exit with the desired status
143 15 50 66     204 if ( !$opts{'-noperldoc'}
      66        
      66        
144             and $opts{'-verbose'} >= 2
145             and !ref($opts{'-input'})
146             and $opts{'-output'} == \*STDOUT )
147             {
148             ## spit out the entire PODs. Might as well invoke perldoc
149 0 0       0 print { $opts{'-output'} } ($opts{'-message'}, "\n") if($opts{'-message'});
  0         0  
150 0 0 0     0 if(defined $opts{-input} && $opts{-input} =~ /^\s*(\S.*?)\s*$/) {
151             # the perldocs back to 5.005 should all have -F
152             # without -F there are warnings in -T scripts
153 0         0 my $f = $1;
154 0         0 my @perldoc_cmd = ($progpath);
155 0 0       0 if ($opts{'-perldocopt'}) {
156 0         0 $opts{'-perldocopt'} =~ s/^\s+|\s+$//g;
157 0         0 push @perldoc_cmd, split(/\s+/, $opts{'-perldocopt'});
158             }
159 0         0 push @perldoc_cmd, ('-F', $f);
160 0 0       0 unshift @perldoc_cmd, $opts{'-perlcmd'} if $opts{'-perlcmd'};
161 0         0 system(@perldoc_cmd);
162 0 0       0 if($?) {
163             # RT16091: fall back to more if perldoc failed
164 0   0     0 system(($Config{pager} || $ENV{PAGER} || '/bin/more'), $1);
165             }
166             } else {
167 0         0 croak "Unspecified input file or insecure argument.\n";
168             }
169             }
170             else {
171 15         211 $parser->parse_from_file($opts{'-input'}, $opts{'-output'});
172             }
173              
174 15 100       2857 exit($opts{'-exitval'}) unless (lc($opts{'-exitval'}) eq 'noexit');
175             }
176              
177             ##---------------------------------------------------------------------------
178              
179             ##-------------------------------
180             ## Method definitions begin here
181             ##-------------------------------
182              
183             sub new {
184 15     15 1 86 my $this = shift;
185 15   33     170 my $class = ref($this) || $this;
186 15         51 my %params = @_;
187 15         105 my $self = {%params};
188 15         126 bless $self, $class;
189 15 50       863 if ($self->can('initialize')) {
190 0         0 $self->initialize();
191             } else {
192             # pass through options to Pod::Text
193 15         42 my %opts;
194 15         94 for (qw(alt code indent loose margin quotes sentence stderr utf8 width)) {
195 150         207 my $val = $params{USAGE_OPTIONS}{"-$_"};
196 150 50       250 $opts{$_} = $val if defined $val;
197             }
198 15         554 $self = $self->SUPER::new(%opts);
199 15         6217 %$self = (%$self, %params);
200             }
201 15         94 return $self;
202             }
203              
204             # This subroutine was copied in whole-cloth from Pod::Select 1.60 in order to
205             # allow the ejection of Pod::Select from the core without breaking Pod::Usage.
206             # -- rjbs, 2013-03-18
207             sub _compile_section_spec {
208 25     25   33 my ($section_spec) = @_;
209 25         20 my (@regexs, $negated);
210              
211             ## Compile the spec into a list of regexs
212 25         27 local $_ = $section_spec;
213 25         79 s{\\\\}{\001}g; ## handle escaped backward slashes
214 25         51 s{\\/}{\002}g; ## handle escaped forward slashes
215              
216             ## Parse the regexs for the heading titles
217 25         126 @regexs = split(/\//, $_, $MAX_HEADING_LEVEL);
218              
219             ## Set default regex for ommitted levels
220 25         101 for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
221 75 100 66     413 $regexs[$i] = '.*' unless ((defined $regexs[$i])
222             && (length $regexs[$i]));
223             }
224             ## Modify the regexs as needed and validate their syntax
225 25         39 my $bad_regexs = 0;
226 25         52 for (@regexs) {
227 75 50       161 $_ .= '.+' if ($_ eq '!');
228 75         124 s{\001}{\\\\}g; ## restore escaped backward slashes
229 75         91 s{\002}{\\/}g; ## restore escaped forward slashes
230 75         146 $negated = s/^\!//; ## check for negation
231 75         6888 eval "m{$_}"; ## check regex syntax
232 75 50       182 if ($@) {
233 0         0 ++$bad_regexs;
234 0         0 carp qq{Bad regular expression /$_/ in "$section_spec": $@\n};
235             }
236             else {
237             ## Add the forward and rear anchors (and put the negator back)
238 75 50       235 $_ = '^' . $_ unless (/^\^/);
239 75 50       167 $_ = $_ . '$' unless (/\$$/);
240 75 100       167 $_ = '!' . $_ if ($negated);
241             }
242             }
243 25 50       151 return (! $bad_regexs) ? [ @regexs ] : undef;
244             }
245              
246             sub select {
247 15     15 0 273 my ($self, @sections) = @_;
248 15 50       458 if ($ISA[0]->can('select')) {
249 0         0 $self->SUPER::select(@sections);
250             } else {
251             # we're using Pod::Simple - need to mimic the behavior of Pod::Select
252 15 50       123 my $add = ($sections[0] eq '+') ? shift(@sections) : '';
253             ## Reset the set of sections to use
254 15 50       94 unless (@sections) {
255 0 0       0 delete $self->{USAGE_SELECT} unless ($add);
256 0         0 return;
257             }
258             $self->{USAGE_SELECT} = []
259 15 50 33     108 unless ($add && $self->{USAGE_SELECT});
260 15         28 my $sref = $self->{USAGE_SELECT};
261             ## Compile each spec
262 15         33 for my $spec (@sections) {
263 25         59 my $cs = _compile_section_spec($spec);
264 25 50       72 if ( defined $cs ) {
265             ## Store them in our sections array
266 25         87 push(@$sref, $cs);
267             } else {
268 0         0 carp qq{Ignoring section spec "$spec"!\n};
269             }
270             }
271             }
272             }
273              
274             # Override Pod::Text->seq_i to return just "arg", not "*arg*".
275 0     0 0 0 sub seq_i { return $_[1] }
276             # Override Pod::Text->cmd_i to return just "arg", not "*arg*".
277             # newer version based on Pod::Simple
278 28     28 0 248 sub cmd_i { return $_[2] }
279              
280             # This overrides the Pod::Text method to do something very akin to what
281             # Pod::Select did as well as the work done below by preprocess_paragraph.
282             # Note that the below is very, very specific to Pod::Text and Pod::Simple.
283             sub _handle_element_end {
284 546     546   89270 my ($self, $element) = @_;
285 546 100 66     1530 if ($element eq 'head1') {
    100          
286 65         164 $self->{USAGE_HEADINGS} = [ $$self{PENDING}[-1][1] ];
287 65 100       247 if ($self->{USAGE_OPTIONS}->{-verbose} < 2) {
288 61         178 $$self{PENDING}[-1][1] =~ s/^\s*SYNOPSIS\s*$/USAGE/;
289             }
290             } elsif ($element =~ /^head(\d+)$/ && $1) { # avoid 0
291 24         40 my $idx = $1 - 1;
292 24 50       46 $self->{USAGE_HEADINGS} = [] unless($self->{USAGE_HEADINGS});
293 24         32 $self->{USAGE_HEADINGS}->[$idx] = $$self{PENDING}[-1][1];
294             # we have to get rid of the lower headings
295 24         19 splice(@{$self->{USAGE_HEADINGS}},$idx+1);
  24         40  
296             }
297 546 100       884 if ($element =~ /^head\d+$/) {
298 89         149 $$self{USAGE_SKIPPING} = 1;
299 89 50 33     232 if (!$$self{USAGE_SELECT} || !@{ $$self{USAGE_SELECT} }) {
300 0         0 $$self{USAGE_SKIPPING} = 0;
301             } else {
302 89         70 my @headings = @{$$self{USAGE_HEADINGS}};
  89         147  
303 89         71 for my $section_spec ( @{$$self{USAGE_SELECT}} ) {
  89         161  
304 132         99 my $match = 1;
305 132         243 for (my $i = 0; $i < $MAX_HEADING_LEVEL; ++$i) {
306 191 100       376 $headings[$i] = '' unless defined $headings[$i];
307 191         177 my $regex = $section_spec->[$i];
308 191         185 my $negated = ($regex =~ s/^\!//);
309 191 100       2423 $match &= ($negated ? ($headings[$i] !~ /${regex}/)
310             : ($headings[$i] =~ /${regex}/));
311 191 100       481 last unless ($match);
312             } # end heading levels
313 132 100       255 if ($match) {
314 27         34 $$self{USAGE_SKIPPING} = 0;
315 27         60 last;
316             }
317             } # end sections
318             }
319              
320             # Try to do some lowercasing instead of all-caps in headings, and use
321             # a colon to end all headings.
322 89 100       224 if($self->{USAGE_OPTIONS}->{-verbose} < 2) {
323 85         133 local $_ = $$self{PENDING}[-1][1];
324 85 100       256 s{([A-Z])([A-Z]+)}{((length($2) > 2) ? $1 : lc($1)) . lc($2)}ge;
  58         331  
325 85 50       392 s/\s*$/:/ unless (/:\s*$/);
326 85         99 $_ .= "\n";
327 85         146 $$self{PENDING}[-1][1] = $_;
328             }
329             }
330 546 100 100     1971 if ($$self{USAGE_SKIPPING} && $element !~ m/^over-|^[BCFILSZ]$/) {
331 232         140 pop @{ $$self{PENDING} };
  232         445  
332             } else {
333 314         632 $self->SUPER::_handle_element_end($element);
334             }
335             }
336              
337             # required for Pod::Simple API
338             sub start_document {
339 15     15 0 49358 my $self = shift;
340 15         206 $self->SUPER::start_document();
341 15 100       528 my $msg = $self->{USAGE_OPTIONS}->{-message} or return 1;
342 1         4 my $out_fh = $self->output_fh();
343 1         30 print $out_fh "$msg\n";
344             }
345              
346             # required for old Pod::Parser API
347             sub begin_pod {
348 0     0 0   my $self = shift;
349 0           $self->SUPER::begin_pod(); ## Have to call superclass
350 0 0         my $msg = $self->{USAGE_OPTIONS}->{-message} or return 1;
351 0           my $out_fh = $self->output_handle();
352 0           print $out_fh "$msg\n";
353             }
354              
355             sub preprocess_paragraph {
356 0     0 0   my $self = shift;
357 0           local $_ = shift;
358 0           my $line = shift;
359             ## See if this is a heading and we aren't printing the entire manpage.
360 0 0 0       if (($self->{USAGE_OPTIONS}->{-verbose} < 2) && /^=head/) {
361             ## Change the title of the SYNOPSIS section to USAGE
362 0           s/^=head1\s+SYNOPSIS\s*$/=head1 USAGE/;
363             ## Try to do some lowercasing instead of all-caps in headings
364 0 0         s{([A-Z])([A-Z]+)}{((length($2) > 2) ? $1 : lc($1)) . lc($2)}ge;
  0            
365             ## Use a colon to end all headings
366 0 0         s/\s*$/:/ unless (/:\s*$/);
367 0           $_ .= "\n";
368             }
369 0           return $self->SUPER::preprocess_paragraph($_);
370             }
371              
372             1; # keep require happy
373              
374             __END__