| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package File::SortedSeek; |
|
2
|
10
|
|
|
10
|
|
129438
|
use strict; |
|
|
10
|
|
|
|
|
26
|
|
|
|
10
|
|
|
|
|
372
|
|
|
3
|
10
|
|
|
10
|
|
52
|
use warnings; |
|
|
10
|
|
|
|
|
104
|
|
|
|
10
|
|
|
|
|
334
|
|
|
4
|
10
|
|
|
10
|
|
20520
|
use Time::Local; |
|
|
10
|
|
|
|
|
22239
|
|
|
|
10
|
|
|
|
|
889
|
|
|
5
|
|
|
|
|
|
|
require Exporter; |
|
6
|
|
|
|
|
|
|
|
|
7
|
10
|
|
|
10
|
|
78
|
use vars qw( @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION ); |
|
|
10
|
|
|
|
|
38
|
|
|
|
10
|
|
|
|
|
21518
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
@ISA = qw( Exporter ); |
|
10
|
|
|
|
|
|
|
@EXPORT = (); |
|
11
|
|
|
|
|
|
|
@EXPORT_OK = qw( alphabetic numeric find_time get_between get_last ); |
|
12
|
|
|
|
|
|
|
%EXPORT_TAGS = ( 'all' => \@EXPORT_OK ); |
|
13
|
|
|
|
|
|
|
$VERSION = '0.015'; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my $descending = 0; |
|
16
|
|
|
|
|
|
|
my $cuddle = 0; |
|
17
|
|
|
|
|
|
|
my $line_length = 80; |
|
18
|
|
|
|
|
|
|
my $error_msg = ''; |
|
19
|
|
|
|
|
|
|
my $silent = 0; |
|
20
|
|
|
|
|
|
|
my $exact_match = 0; |
|
21
|
|
|
|
|
|
|
my %months = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, |
|
22
|
|
|
|
|
|
|
May => 4, Jun => 5, Jul => 6, Aug => 7, |
|
23
|
|
|
|
|
|
|
Sep => 8, Oct => 9, Nov => 10,Dec => 11); |
|
24
|
|
|
|
|
|
|
my $default_rec_sep = qw/\015\012|\015|\012/; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
# some subs to set optional vars OO style |
|
27
|
5
|
|
|
5
|
1
|
48254
|
sub set_cuddle { $cuddle = 1 }; |
|
28
|
4
|
|
|
4
|
1
|
788
|
sub set_no_cuddle { $cuddle = 0 }; |
|
29
|
2
|
|
|
2
|
1
|
17052
|
sub set_descending { $descending = 1 }; |
|
30
|
0
|
|
|
0
|
1
|
0
|
sub set_ascending { $descending = 0 }; |
|
31
|
0
|
|
|
0
|
0
|
0
|
sub set_max_tries { }; # legacy method, no effect |
|
32
|
0
|
|
|
0
|
0
|
0
|
sub set_line_length { }; # legacy method, no effect |
|
33
|
9
|
|
|
9
|
1
|
241
|
sub set_silent { $silent = 1 }; |
|
34
|
0
|
|
|
0
|
1
|
0
|
sub set_verbose { $silent = 0 }; |
|
35
|
3
|
|
|
3
|
1
|
994
|
sub was_exact { $exact_match }; |
|
36
|
0
|
|
|
0
|
1
|
0
|
sub error { $error_msg; }; |
|
37
|
|
|
|
|
|
|
|
|
38
|
6456
|
100
|
|
6456
|
|
14322
|
sub _alphabetic_compare { $descending ? $_[1] cmp $_[0] : $_[0] cmp $_[1] } |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub alphabetic { |
|
41
|
15
|
|
|
15
|
1
|
21486
|
local *FILE = shift; |
|
42
|
15
|
|
|
|
|
32
|
my $string = shift; |
|
43
|
15
|
|
|
|
|
23
|
my $munge_ref = shift; |
|
44
|
15
|
|
|
|
|
25
|
$error_msg = ''; |
|
45
|
15
|
|
|
|
|
58
|
_look( *FILE, $string, \&_alphabetic_compare, $munge_ref ); |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
9304
|
100
|
|
9304
|
|
25797
|
sub _numeric_compare { $descending ? $_[1] <=> $_[0] : $_[0] <=> $_[1] } |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub numeric { |
|
51
|
17
|
|
|
17
|
1
|
224451
|
local *FILE = shift; |
|
52
|
17
|
|
|
|
|
32
|
my $number = shift; |
|
53
|
17
|
|
|
|
|
32
|
my $munge_ref = shift; |
|
54
|
17
|
|
|
|
|
30
|
$error_msg = ''; |
|
55
|
17
|
|
|
|
|
72
|
_look( *FILE, $number, \&_numeric_compare, $munge_ref ); |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub find_time { |
|
59
|
9
|
|
|
9
|
1
|
191614
|
local *FILE = shift; |
|
60
|
9
|
|
33
|
|
|
43
|
my $find = shift || time; |
|
61
|
9
|
|
|
|
|
17
|
my $not_gmtime = shift; |
|
62
|
9
|
|
|
|
|
153
|
$error_msg = ''; |
|
63
|
9
|
100
|
|
|
|
175
|
$find = get_epoch_seconds($find,$not_gmtime) unless $find =~ m/^[\d.]+$/; |
|
64
|
9
|
|
|
|
|
148
|
_look( *FILE, $find, \&_numeric_compare, \&get_epoch_seconds ); |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub get_epoch_seconds { |
|
68
|
759
|
|
|
759
|
1
|
1376
|
my ($line, $not_gmtime) = @_; |
|
69
|
759
|
50
|
|
|
|
1505
|
return undef unless defined $line; |
|
70
|
759
|
|
|
|
|
1121
|
my ($wday,$mon,$mday,$hours,$min,$sec,$year); |
|
71
|
|
|
|
|
|
|
# look for asctime format: Tue May 27 15:45:00 2008 |
|
72
|
|
|
|
|
|
|
# ignore wday token as this is often dropped ie linux kernel messages |
|
73
|
759
|
50
|
|
|
|
8498
|
if ($line =~ m/(\w{3})\s+(\d{1,2})\s+(\d\d):(\d\d):(\d\d)\s+(\d{4})/ ) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
74
|
759
|
|
|
|
|
33098
|
($mon,$mday,$hours,$min,$sec,$year) = ($1,$2,$3,$4,$5,$6); |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
# look for apache time format: [21/May/2008:17:49:39 +1000] |
|
77
|
|
|
|
|
|
|
# ignore the time offset |
|
78
|
|
|
|
|
|
|
elsif($line =~ m!\[(\d{1,2})/(\w{3})/(\d{4}):(\d\d):(\d\d):(\d\d)!x ) { |
|
79
|
0
|
|
|
|
|
0
|
($mday,$mon,$year,$hours,$min,$sec) = ($1,$2,$3,$4,$5,$6); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
# look for straight epochtime data (ie squid log) |
|
82
|
|
|
|
|
|
|
elsif($line =~ m/^(\d+)/) { |
|
83
|
0
|
|
|
|
|
0
|
return $1; |
|
84
|
|
|
|
|
|
|
} |
|
85
|
759
|
50
|
|
|
|
1742
|
unless ($year) { |
|
86
|
0
|
|
|
|
|
0
|
$error_msg = "Unable to find time like string in line:\n$line"; |
|
87
|
0
|
0
|
|
|
|
0
|
warn $error_msg unless $silent; |
|
88
|
0
|
|
|
|
|
0
|
return undef; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
759
|
|
|
|
|
1743
|
$mon = $months{$mon}; # convert to numerical months 0 - 11 |
|
91
|
759
|
50
|
|
|
|
2540
|
return $not_gmtime ? timelocal($sec,$min,$hours,$mday,$mon,$year): |
|
92
|
|
|
|
|
|
|
timegm($sec,$min,$hours,$mday,$mon,$year); |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub get_between { |
|
96
|
7
|
|
|
7
|
1
|
82
|
local *FILE = shift; |
|
97
|
7
|
|
100
|
|
|
41
|
my $begin = shift || 0; |
|
98
|
7
|
|
50
|
|
|
31
|
my $finish = shift || 0; |
|
99
|
7
|
|
33
|
|
|
53
|
my $rec_sep = shift || $default_rec_sep; |
|
100
|
7
|
|
|
|
|
17
|
$error_msg = ''; |
|
101
|
7
|
50
|
|
|
|
39
|
($begin , $finish) = ($finish, $begin) if $begin > $finish; |
|
102
|
7
|
|
|
|
|
14
|
my $bytes = $finish - $begin; |
|
103
|
7
|
|
|
|
|
34
|
sysseek FILE, $begin, 0; |
|
104
|
7
|
|
|
|
|
108
|
my $read = sysread(FILE, my $buffer, $bytes); |
|
105
|
7
|
50
|
|
|
|
28
|
if ( $read < $bytes ) { |
|
106
|
0
|
|
|
|
|
0
|
$error_msg = "Short read\nWanted: $bytes Got: $read\n"; |
|
107
|
0
|
0
|
|
|
|
0
|
warn $error_msg unless $silent; |
|
108
|
0
|
|
|
|
|
0
|
return undef; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
7
|
|
|
|
|
27
|
$buffer = substr $buffer, 0, $bytes; |
|
111
|
7
|
|
|
|
|
383
|
my @lines = split $rec_sep, $buffer; |
|
112
|
7
|
50
|
|
|
|
78
|
return wantarray ? @lines : [ @lines ]; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub get_last { |
|
116
|
4
|
|
|
4
|
1
|
357383
|
local *FILE = shift; |
|
117
|
4
|
|
|
|
|
7
|
my $num_lines = shift; |
|
118
|
4
|
|
33
|
|
|
20
|
my $rec_sep = shift || $default_rec_sep; |
|
119
|
4
|
|
|
|
|
6
|
$error_msg = ''; |
|
120
|
4
|
50
|
|
|
|
54
|
my @stat = stat(FILE) or return undef; |
|
121
|
4
|
|
|
|
|
10
|
my($size,$blksize) = @stat[7,11]; |
|
122
|
4
|
|
50
|
|
|
13
|
$blksize ||= 8192; |
|
123
|
|
|
|
|
|
|
# grab the first chunk back from eof at block offset |
|
124
|
4
|
|
33
|
|
|
11
|
my $pos = $size - (($size % $blksize)|| $blksize ); |
|
125
|
4
|
|
|
|
|
5
|
my $file = ''; |
|
126
|
4
|
|
|
|
|
7
|
my ($buf, $lines); |
|
127
|
4
|
|
|
|
|
3
|
for(;;) { |
|
128
|
18
|
50
|
|
|
|
36
|
$pos = 0 if $pos < 0; |
|
129
|
18
|
|
|
|
|
63
|
sysseek(FILE,$pos,0); |
|
130
|
18
|
50
|
|
|
|
138
|
sysread(FILE, $buf, $blksize) or last; # returns 0 at eof; |
|
131
|
18
|
|
|
|
|
731
|
$file = $buf.$file; |
|
132
|
18
|
|
|
|
|
7182
|
my $lines = () = $file =~ m/$rec_sep/g; |
|
133
|
18
|
100
|
100
|
|
|
938
|
last if $lines > $num_lines or $pos == 0; |
|
134
|
14
|
|
|
|
|
17
|
$pos -= $blksize; |
|
135
|
|
|
|
|
|
|
} |
|
136
|
4
|
|
|
|
|
1733
|
my @file = split /$rec_sep/, $file; |
|
137
|
4
|
100
|
|
|
|
68
|
if ( $num_lines > @file ) { |
|
138
|
2
|
|
|
|
|
8
|
$error_msg = "Unable to find $num_lines\n"; |
|
139
|
2
|
50
|
|
|
|
7
|
warn $error_msg unless $silent; |
|
140
|
2
|
100
|
|
|
|
264
|
return wantarray ? @file : \@file; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
else { |
|
143
|
2
|
|
|
|
|
4
|
$num_lines = $#file - $num_lines + 1; |
|
144
|
2
|
100
|
|
|
|
51
|
return wantarray ? @file[$num_lines..$#file] : [@file[$num_lines..$#file]]; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Modified version of Perl Search::Dict's look() |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub _look { |
|
151
|
41
|
|
|
41
|
|
72
|
local *FILE = shift; |
|
152
|
41
|
|
|
|
|
90
|
my($key,$comp,$xfrm) = @_; |
|
153
|
41
|
|
|
|
|
61
|
local $_; |
|
154
|
41
|
50
|
|
|
|
149
|
return undef if not defined $key; |
|
155
|
41
|
50
|
|
|
|
1013
|
my @stat = stat(FILE) or return undef; |
|
156
|
41
|
|
|
|
|
130
|
my($size, $blksize) = @stat[7,11]; |
|
157
|
41
|
|
50
|
|
|
127
|
$blksize ||= 8192; |
|
158
|
|
|
|
|
|
|
# find the right block |
|
159
|
41
|
|
|
|
|
135
|
my($min, $max) = (0, int($size / $blksize)); |
|
160
|
41
|
|
|
|
|
59
|
my $mid; |
|
161
|
41
|
|
|
|
|
145
|
while ($max - $min > 1) { |
|
162
|
109
|
|
|
|
|
179
|
$mid = int(($max + $min) / 2); |
|
163
|
109
|
50
|
|
|
|
1555
|
seek(FILE, $mid * $blksize, 0) or return undef; |
|
164
|
109
|
50
|
|
|
|
1721
|
if $mid; # probably a partial line |
|
165
|
109
|
|
|
|
|
259
|
$_ = ; |
|
166
|
109
|
100
|
|
|
|
275
|
$_ = $xfrm->($_) if $xfrm; |
|
167
|
109
|
|
|
|
|
1346
|
chomp; |
|
168
|
109
|
100
|
66
|
|
|
411
|
(defined($_) && $comp->($_, $key) < 0) ? $min = $mid : $max = $mid; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
# find the right line |
|
171
|
41
|
|
|
|
|
64
|
$min *= $blksize; |
|
172
|
41
|
50
|
|
|
|
387
|
seek(FILE,$min,0) or return undef; |
|
173
|
41
|
100
|
|
|
|
210
|
if $min; # probably a partial line |
|
174
|
41
|
|
|
|
|
77
|
my $prev_min = $min; |
|
175
|
41
|
|
|
|
|
48
|
for (;;) { |
|
176
|
15656
|
|
|
|
|
18299
|
$min = tell(FILE); |
|
177
|
15656
|
100
|
|
|
|
32891
|
defined($_ = ) or last; |
|
178
|
15651
|
100
|
|
|
|
29812
|
$_ = $xfrm->($_) if $xfrm; |
|
179
|
15651
|
|
|
|
|
43057
|
chomp; |
|
180
|
15651
|
|
|
|
|
23773
|
my $cmp = $comp->($_, $key); |
|
181
|
15651
|
100
|
|
|
|
26395
|
$exact_match = $cmp==0 ? 1 : 0; |
|
182
|
15651
|
100
|
100
|
|
|
62461
|
if(!$cuddle and $cmp >= 0){ |
|
183
|
31
|
|
|
|
|
333
|
seek(FILE,$min,0); |
|
184
|
31
|
|
|
|
|
258
|
return $min; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
15620
|
100
|
100
|
|
|
35081
|
if($cuddle and $cmp > 0){ |
|
187
|
5
|
|
|
|
|
55
|
seek(FILE,$prev_min,0); |
|
188
|
5
|
|
|
|
|
44
|
return $prev_min; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
15615
|
|
|
|
|
18262
|
$prev_min = $min; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
5
|
|
|
|
|
70
|
return undef; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
1; |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
__END__ |