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__ |