line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package IO::Pager; |
2
|
|
|
|
|
|
|
our $VERSION = "2.10"; #Untouched since 1.03 |
3
|
|
|
|
|
|
|
|
4
|
8
|
|
|
8
|
|
628605
|
use 5.008; #At least, for decent perlio, and other modernisms |
|
8
|
|
|
|
|
83
|
|
5
|
8
|
|
|
8
|
|
50
|
use strict; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
213
|
|
6
|
8
|
|
|
8
|
|
42
|
use warnings; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
271
|
|
7
|
8
|
|
|
8
|
|
42
|
use base qw( Tie::Handle ); |
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
3967
|
|
8
|
8
|
|
|
8
|
|
20512
|
use Env qw( PAGER ); |
|
8
|
|
|
|
|
17746
|
|
|
8
|
|
|
|
|
47
|
|
9
|
8
|
|
|
8
|
|
1299
|
use File::Spec; |
|
8
|
|
|
|
|
18
|
|
|
8
|
|
|
|
|
161
|
|
10
|
8
|
|
|
8
|
|
40
|
use PerlIO; |
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
57
|
|
11
|
8
|
|
|
8
|
|
2776
|
use Symbol; |
|
8
|
|
|
|
|
4485
|
|
|
8
|
|
|
|
|
524
|
|
12
|
|
|
|
|
|
|
|
13
|
8
|
|
|
8
|
|
4643
|
use overload '+' => "PID", bool=> "PID"; |
|
8
|
|
|
|
|
3871
|
|
|
8
|
|
|
|
|
53
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $SIGPIPE; |
16
|
|
|
|
|
|
|
#use Carp; $SIG{__WARN__} = sub{ print STDERR @_, Carp::longmess(),"\n\n"; }; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub find_pager { |
19
|
|
|
|
|
|
|
# Return the name (or path) of a pager that IO::Pager can use |
20
|
14
|
|
|
14
|
0
|
115754
|
my $io_pager; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#Permit explicit use of pure perl pager |
23
|
14
|
|
|
|
|
31
|
local $_ = 'IO::Pager::less'; |
24
|
14
|
50
|
33
|
|
|
124
|
return $_ if (defined($_[0]) && ($_[0] eq $_)) or |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
25
|
|
|
|
|
|
|
(defined($PAGER) && ($PAGER eq $_)); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Use File::Which if available (strongly recommended) |
28
|
14
|
|
|
|
|
159
|
my $which = eval { require File::Which }; |
|
14
|
|
|
|
|
3766
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# Look for pager in PAGER first |
31
|
14
|
100
|
|
|
|
8220
|
if ($PAGER) { |
32
|
|
|
|
|
|
|
# Strip arguments e.g. 'less --quiet' |
33
|
4
|
|
|
|
|
36
|
my ($pager, @options) = (split ' ', $PAGER); |
34
|
4
|
|
|
|
|
29
|
$pager = _check_pagers([$pager], $which); |
35
|
4
|
100
|
|
|
|
21
|
$io_pager = join ' ', ($pager, @options) if defined $pager; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Then search pager amongst usual suspects |
39
|
14
|
100
|
|
|
|
133
|
if (not defined $io_pager) { |
40
|
11
|
|
|
|
|
32
|
my @pagers = ('/etc/alternatives/pager', |
41
|
|
|
|
|
|
|
'/usr/local/bin/less', '/usr/bin/less', '/usr/bin/more'); |
42
|
11
|
|
|
|
|
32
|
$io_pager = _check_pagers(\@pagers, $which) |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Then check PATH for other pagers |
46
|
14
|
50
|
33
|
|
|
53
|
if ( (not defined $io_pager) && $which ) { |
47
|
0
|
|
|
|
|
0
|
my @pagers = ('less', 'most', 'w3m', 'lv', 'pg', 'more'); |
48
|
0
|
|
|
|
|
0
|
$io_pager = _check_pagers(\@pagers, $which ); |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# If all else fails, default to more (actually IO::Pager::less first) |
52
|
14
|
|
50
|
|
|
34
|
$io_pager ||= 'more'; |
53
|
|
|
|
|
|
|
|
54
|
14
|
|
|
|
|
61
|
return $io_pager; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub _check_pagers { |
58
|
15
|
|
|
15
|
|
32
|
my ($pagers, $which) = @_; |
59
|
|
|
|
|
|
|
# Return the first pager in the list that is usable. For each given pager, |
60
|
|
|
|
|
|
|
# given a pager name, try to finds its full path with File::Which if possible. |
61
|
|
|
|
|
|
|
# Given a pager path, verify that it exists. |
62
|
15
|
|
|
|
|
28
|
my $io_pager = undef; |
63
|
15
|
|
|
|
|
32
|
for my $pager (@$pagers) { |
64
|
|
|
|
|
|
|
# Get full path |
65
|
15
|
|
|
|
|
21
|
my $loc; |
66
|
15
|
100
|
66
|
|
|
241
|
if ( $which && (not File::Spec->file_name_is_absolute($pager)) ) { |
67
|
2
|
|
|
|
|
8
|
$loc = File::Which::which($pager); |
68
|
|
|
|
|
|
|
} else { |
69
|
13
|
|
|
|
|
26
|
$loc = $pager; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
# Test that full path is valid (some platforms don't do -x so we use -e) |
72
|
15
|
100
|
66
|
|
|
795
|
if ( defined($loc) && (-e $loc) ) { |
73
|
14
|
|
|
|
|
38
|
$io_pager = $loc; |
74
|
14
|
|
|
|
|
33
|
last; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
} |
77
|
15
|
|
|
|
|
37
|
return $io_pager; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
#Should have this as first block for clarity, but not with its use of a sub |
81
|
|
|
|
|
|
|
BEGIN { # Set the $ENV{PAGER} to something reasonable |
82
|
8
|
|
50
|
8
|
|
3806
|
our $oldPAGER = $PAGER || ''; |
83
|
8
|
|
|
|
|
197
|
$PAGER = find_pager(); |
84
|
|
|
|
|
|
|
|
85
|
8
|
50
|
33
|
|
|
134
|
if( ($PAGER =~ 'more' and $oldPAGER ne 'more') or |
|
|
|
33
|
|
|
|
|
86
|
|
|
|
|
|
|
$PAGER eq 'IO::Pager::less' ){ |
87
|
0
|
|
|
|
|
0
|
my $io_pager = $PAGER; |
88
|
0
|
|
|
|
|
0
|
eval "use IO::Pager::less"; |
89
|
0
|
0
|
0
|
|
|
0
|
$PAGER = $io_pager if $@ or not defined $PAGER; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
#Factory |
95
|
|
|
|
|
|
|
sub open(*;$@) { # FH, [MODE], [CLASS] |
96
|
0
|
|
|
0
|
1
|
0
|
my $args = {procedural=>1}; |
97
|
0
|
0
|
|
|
|
0
|
$args->{mode} = splice(@_, 1, 1) if scalar(@_) == 3; |
98
|
0
|
0
|
|
|
|
0
|
$args->{subclass} = pop if scalar(@_) == 2; |
99
|
0
|
|
|
|
|
0
|
&new(undef, @_, $args); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
#Alternate entrance: drop class but leave FH, subclass |
103
|
|
|
|
|
|
|
sub new(*;$@) { # FH, [MODE], [CLASS] |
104
|
4
|
|
|
4
|
1
|
113079
|
shift; |
105
|
|
|
|
|
|
|
|
106
|
4
|
|
|
|
|
8
|
my %args; |
107
|
4
|
50
|
|
|
|
30
|
if( ref($_[-1]) eq 'HASH' ){ |
|
|
100
|
|
|
|
|
|
108
|
0
|
|
|
|
|
0
|
%args = %{pop()}; |
|
0
|
|
|
|
|
0
|
|
109
|
|
|
|
|
|
|
#warn "REMAINDER? (@_)", scalar @_; |
110
|
0
|
|
|
|
|
0
|
push(@_, $args{procedural}); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
elsif( defined($_[1]) ){ |
113
|
2
|
50
|
|
|
|
9
|
$args{mode} = splice(@_, 1, 1) if $_[1] =~ /^:/; |
114
|
2
|
50
|
|
|
|
10
|
$args{subclass} = pop if exists($_[1]); |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
#Leave filehandle in @_ for pass by reference to allow gensym |
118
|
4
|
|
100
|
|
|
26
|
$args{subclass} ||= 'IO::Pager::Unbuffered'; |
119
|
4
|
|
|
|
|
15
|
$args{subclass} =~ s/^(?!IO::Pager::)/IO::Pager::/; |
120
|
4
|
50
|
|
|
|
251
|
eval "require $args{subclass}" or die "Could not load $args{subclass}: $@\n"; |
121
|
4
|
|
|
|
|
27
|
my $token = $args{subclass}->new(@_); |
122
|
|
|
|
|
|
|
|
123
|
2
|
50
|
|
|
|
181
|
if( defined($args{mode}) ){ |
124
|
0
|
|
|
|
|
0
|
$args{mode} =~ s/^\|-//; |
125
|
0
|
|
|
|
|
0
|
$token->BINMODE($args{mode}); |
126
|
|
|
|
|
|
|
} |
127
|
2
|
|
|
|
|
171
|
return $token; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub _init{ # CLASS, [FH] ## Note reversal of order due to CLASS from new() |
132
|
|
|
|
|
|
|
#Assign by reference if empty scalar given as filehandle |
133
|
4
|
100
|
|
4
|
|
18
|
$_[1] = gensym() if !defined($_[1]); |
134
|
|
|
|
|
|
|
|
135
|
8
|
|
|
8
|
|
3252
|
no strict 'refs'; |
|
8
|
|
|
|
|
17
|
|
|
8
|
|
|
|
|
1643
|
|
136
|
4
|
|
33
|
|
|
44
|
$_[1] ||= *{select()}; |
|
0
|
|
|
|
|
0
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Are we on a TTY? STDOUT & STDERR are separately bound |
139
|
4
|
100
|
|
|
|
30
|
if ( defined( my $FHn = fileno($_[1]) ) ) { |
140
|
2
|
50
|
|
|
|
12
|
if ( $FHn == fileno(STDOUT) ) { |
141
|
2
|
50
|
|
|
|
38
|
die '!TTY' unless -t $_[1]; |
142
|
|
|
|
|
|
|
} |
143
|
0
|
0
|
|
|
|
0
|
if ( $FHn == fileno(STDERR) ) { |
144
|
0
|
0
|
|
|
|
0
|
die '!TTY' unless -t $_[1]; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
#XXX This allows us to have multiple pseudo-STDOUT |
149
|
|
|
|
|
|
|
#return 0 unless -t STDOUT; |
150
|
|
|
|
|
|
|
|
151
|
2
|
|
|
|
|
8
|
return ($_[0], $_[1]); |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Methods required for implementing a tied filehandle class |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub TIEHANDLE { |
158
|
2
|
|
|
2
|
|
6
|
my ($class, $tied_fh) = @_; |
159
|
2
|
100
|
|
|
|
13
|
unless ( $PAGER ){ |
160
|
1
|
|
|
|
|
28
|
die "The PAGER environment variable is not defined, you may need to set it manually."; |
161
|
|
|
|
|
|
|
} |
162
|
1
|
|
|
|
|
11
|
my($real_fh, $child, $dupe_fh); |
163
|
|
|
|
|
|
|
# XXX What about localized GLOBs?! |
164
|
|
|
|
|
|
|
# if( $tied_fh =~ /\*(?:\w+::)?STD(?:OUT|ERR)$/ ){ |
165
|
|
|
|
|
|
|
# open($dupe_fh, '>&', $tied_fh) or warn "Unable to dupe $tied_fh"; |
166
|
|
|
|
|
|
|
# } |
167
|
8
|
|
|
8
|
|
54
|
do{ no warnings; $child = CORE::open($real_fh, '|-', $PAGER) }; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
6544
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
7
|
|
168
|
1
|
50
|
|
|
|
1995
|
if ( $child ){ |
169
|
0
|
|
|
|
|
0
|
my @oLayers = PerlIO::get_layers($tied_fh, details=>1, output=>1); |
170
|
0
|
|
|
|
|
0
|
my $layers = ''; |
171
|
0
|
|
|
|
|
0
|
for(my $i=0;$i<$#oLayers;$i+=3){ |
172
|
|
|
|
|
|
|
#An extra base layer requires more keystrokes to exit |
173
|
0
|
0
|
0
|
|
|
0
|
next if $oLayers[$i] =~ /unix|stdio/ && !defined($oLayers[+1]); |
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
0
|
$layers .= ":$oLayers[$i]"; |
176
|
0
|
0
|
|
|
|
0
|
$layers .= '(' . ($oLayers[$i+1]) . ')' if defined($oLayers[$i+1]); |
177
|
|
|
|
|
|
|
} |
178
|
0
|
|
|
|
|
0
|
CORE::binmode($real_fh, $layers); |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
else{ |
181
|
1
|
|
|
|
|
51
|
die "Could not pipe to PAGER ('$PAGER'): $!\n"; |
182
|
|
|
|
|
|
|
} |
183
|
0
|
|
|
|
|
|
return bless { |
184
|
|
|
|
|
|
|
'real_fh' => $real_fh, |
185
|
|
|
|
|
|
|
# 'dupe_fh' => $dupe_fh, |
186
|
|
|
|
|
|
|
'tied_fh' => "$tied_fh", #Avoid self-reference leak |
187
|
|
|
|
|
|
|
'child' => $child, |
188
|
|
|
|
|
|
|
'pager' => $PAGER, |
189
|
|
|
|
|
|
|
}, $class; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub BINMODE { |
194
|
0
|
|
|
0
|
|
|
my ($self, $layer) = @_; |
195
|
0
|
0
|
|
|
|
|
if( $layer =~ /^:LOG\((>{0,2})(.*)\)$/ ){ |
196
|
0
|
0
|
0
|
|
|
|
CORE::open($self->{LOG}, $1||'>', $2||"$$.log") or die $!; |
|
|
|
0
|
|
|
|
|
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
else{ |
199
|
0
|
|
0
|
|
|
|
CORE::binmode($self->{real_fh}, $layer||':raw'); |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub WNOHANG(); |
204
|
|
|
|
|
|
|
sub EOF { |
205
|
0
|
|
|
0
|
|
|
my $self = shift; |
206
|
|
|
|
|
|
|
|
207
|
0
|
0
|
|
|
|
|
unless( defined($SIGPIPE) ){ |
208
|
0
|
|
|
|
|
|
eval 'use POSIX ":sys_wait_h";'; |
209
|
0
|
|
|
|
|
|
$SIGPIPE = 0; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
0
|
0
|
|
0
|
|
|
$SIG{PIPE} = sub { $SIGPIPE = 1 unless $ENV{IP_EOF}; |
213
|
0
|
|
|
|
|
|
CORE::close($self->{real_fh}); |
214
|
0
|
|
|
|
|
|
waitpid($self->{child}, WNOHANG); |
215
|
0
|
|
|
|
|
|
CORE::open($self->{real_fh}, '>&1'); |
216
|
|
|
|
|
|
|
|
217
|
0
|
|
|
|
|
|
close($self->{LOG}); |
218
|
0
|
|
|
|
|
|
}; |
219
|
0
|
|
|
|
|
|
return $SIGPIPE; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub PRINT { |
224
|
0
|
|
|
0
|
|
|
my ($self, @args) = @_; |
225
|
0
|
0
|
|
|
|
|
CORE::print {$self->{LOG}} @args if exists($self->{LOG}); |
|
0
|
|
|
|
|
|
|
226
|
0
|
0
|
|
|
|
|
CORE::print {$self->{real_fh}} @args or die "Could not print to PAGER: $!\n"; |
|
0
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub PRINTF { |
230
|
0
|
|
|
0
|
|
|
my ($self, $format, @args) = @_; |
231
|
0
|
|
|
|
|
|
$self->PRINT(sprintf($format, @args)); |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub say { |
236
|
0
|
|
|
0
|
0
|
|
my ($self, @args) = @_; |
237
|
0
|
|
|
|
|
|
$args[-1] .= "\n"; |
238
|
0
|
|
|
|
|
|
$self->PRINT(@args); |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub WRITE { |
242
|
0
|
|
|
0
|
|
|
my ($self, $scalar, $length, $offset) = @_; |
243
|
0
|
|
0
|
|
|
|
$self->PRINT(substr($scalar, $offset||0, $length)); |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
sub TELL { |
248
|
|
|
|
|
|
|
#Buffered classes provide their own, and others may use this in another way |
249
|
0
|
|
|
0
|
|
|
return undef; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub FILENO { |
254
|
0
|
|
|
0
|
|
|
CORE::fileno($_[0]->{real_fh}); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub CLOSE { |
258
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
259
|
0
|
|
|
|
|
|
CORE::close($self->{real_fh}); |
260
|
|
|
|
|
|
|
# untie($self->{tied_fh}); |
261
|
|
|
|
|
|
|
# *{$self->{tied_fh}} = *{$self->{dupe_fh}}; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
8
|
|
|
8
|
|
81
|
{ no warnings 'once'; *DESTROY = \&CLOSE; } |
|
8
|
|
|
|
|
17
|
|
|
8
|
|
|
|
|
824
|
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
#Non-IO methods |
268
|
|
|
|
|
|
|
sub PID{ |
269
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
270
|
0
|
|
|
|
|
|
return $self->{child}; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
#Provide lowercase aliases for accessors |
275
|
|
|
|
|
|
|
foreach my $method ( qw(BINMODE CLOSE EOF PRINT PRINTF TELL WRITE PID) ){ |
276
|
8
|
|
|
8
|
|
85
|
no strict 'refs'; |
|
8
|
|
|
|
|
26
|
|
|
8
|
|
|
|
|
594
|
|
277
|
|
|
|
|
|
|
*{lc($method)} = \&{$method}; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
1; |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
__END__ |