line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
4
|
|
|
4
|
|
4733
|
use 5.006; |
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
168
|
|
2
|
4
|
|
|
4
|
|
23
|
use strict; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
148
|
|
3
|
4
|
|
|
4
|
|
23
|
use warnings; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
294
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package File::Marker; |
6
|
|
|
|
|
|
|
# ABSTRACT: Set and jump between named position markers on a filehandle |
7
|
|
|
|
|
|
|
our $VERSION = '0.14'; # VERSION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our @ISA = qw( IO::File ); |
10
|
|
|
|
|
|
|
|
11
|
4
|
|
|
4
|
|
23
|
use Carp; |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
396
|
|
12
|
4
|
|
|
4
|
|
3763
|
use IO::File; |
|
4
|
|
|
|
|
39221
|
|
|
4
|
|
|
|
|
741
|
|
13
|
4
|
|
|
4
|
|
35
|
use Scalar::Util 1.09 qw( refaddr weaken ); |
|
4
|
|
|
|
|
113
|
|
|
4
|
|
|
|
|
4037
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
16
|
|
|
|
|
|
|
# Inside-out data storage |
17
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my %MARKS = (); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# Track objects for thread-safety |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my %REGISTRY = (); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
26
|
|
|
|
|
|
|
# new() |
27
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub new { |
30
|
5
|
|
|
5
|
1
|
2978
|
my $class = shift; |
31
|
5
|
|
|
|
|
30
|
my $self = IO::File->new(); |
32
|
5
|
|
|
|
|
197
|
bless $self, $class; |
33
|
5
|
|
|
|
|
33
|
weaken( $REGISTRY{ refaddr $self } = $self ); |
34
|
5
|
100
|
|
|
|
27
|
$self->open(@_) if @_; |
35
|
5
|
|
|
|
|
20
|
return $self; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
39
|
|
|
|
|
|
|
# open() |
40
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub open { |
43
|
7
|
|
|
7
|
1
|
1207
|
my $self = shift; |
44
|
7
|
|
|
|
|
26
|
$MARKS{ refaddr $self } = {}; |
45
|
7
|
|
|
|
|
43
|
$self->SUPER::open(@_); |
46
|
7
|
|
|
|
|
517
|
$MARKS{ refaddr $self }{'LAST'} = $self->getpos; |
47
|
7
|
|
|
|
|
26
|
return 1; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
51
|
|
|
|
|
|
|
# set_marker() |
52
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub set_marker { |
55
|
11
|
|
|
11
|
1
|
2810
|
my ( $self, $mark ) = @_; |
56
|
|
|
|
|
|
|
|
57
|
11
|
100
|
|
|
|
62
|
croak "Can't set marker on closed filehandle" |
58
|
|
|
|
|
|
|
if !$self->opened; |
59
|
|
|
|
|
|
|
|
60
|
10
|
100
|
|
|
|
365
|
croak "Can't set special marker 'LAST'" |
61
|
|
|
|
|
|
|
if $mark eq 'LAST'; |
62
|
|
|
|
|
|
|
|
63
|
9
|
|
|
|
|
43
|
my $position = $self->getpos; |
64
|
|
|
|
|
|
|
|
65
|
9
|
50
|
|
|
|
23
|
croak "Couldn't set marker '$mark': couldn't locate position in file" |
66
|
|
|
|
|
|
|
if !defined $position; |
67
|
|
|
|
|
|
|
|
68
|
9
|
|
|
|
|
47
|
$MARKS{ refaddr $self }{$mark} = $self->getpos; |
69
|
|
|
|
|
|
|
|
70
|
9
|
|
|
|
|
31
|
return 1; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
74
|
|
|
|
|
|
|
# goto_marker() |
75
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub goto_marker { |
78
|
14
|
|
|
14
|
1
|
4060
|
my ( $self, $mark ) = @_; |
79
|
|
|
|
|
|
|
|
80
|
14
|
100
|
|
|
|
108
|
croak "Can't goto marker on closed filehandle" |
81
|
|
|
|
|
|
|
if !$self->opened; |
82
|
|
|
|
|
|
|
|
83
|
13
|
100
|
|
|
|
526
|
croak "Unknown file marker '$mark'" |
84
|
|
|
|
|
|
|
if !exists $MARKS{ refaddr $self}{$mark}; |
85
|
|
|
|
|
|
|
|
86
|
12
|
|
|
|
|
76
|
my $old_position = $self->getpos; # save for LAST |
87
|
|
|
|
|
|
|
|
88
|
12
|
|
|
|
|
306
|
my $rc = $self->setpos( $MARKS{ refaddr $self }{$mark} ); |
89
|
|
|
|
|
|
|
|
90
|
12
|
50
|
|
|
|
32
|
croak "Couldn't goto marker '$mark': could not seek to location in file" |
91
|
|
|
|
|
|
|
if !defined $rc; |
92
|
|
|
|
|
|
|
|
93
|
12
|
|
|
|
|
55
|
$MARKS{ refaddr $self }{'LAST'} = $old_position; |
94
|
|
|
|
|
|
|
|
95
|
12
|
|
|
|
|
162
|
return 1; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
99
|
|
|
|
|
|
|
# markers() |
100
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
sub markers { |
103
|
2
|
|
|
2
|
1
|
657
|
my $self = shift; |
104
|
2
|
|
|
|
|
4
|
return keys %{ $MARKS{ refaddr $self } }; |
|
2
|
|
|
|
|
27
|
|
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
108
|
|
|
|
|
|
|
# save_markers() |
109
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
sub save_markers { |
112
|
1
|
|
|
1
|
1
|
3
|
my ( $self, $filename ) = @_; |
113
|
1
|
50
|
|
|
|
6
|
my $outfile = IO::File->new( $filename, "w" ) |
114
|
|
|
|
|
|
|
or croak "Couldn't open $filename for writing"; |
115
|
1
|
|
|
|
|
149
|
my $markers = $MARKS{ refaddr $self }; |
116
|
1
|
|
|
|
|
5
|
for my $mark ( keys %$markers ) { |
117
|
6
|
100
|
|
|
|
60
|
next if $mark eq 'LAST'; |
118
|
5
|
|
|
|
|
23
|
print $outfile "$mark\n"; |
119
|
5
|
|
|
|
|
22
|
print $outfile unpack( "H*", $markers->{$mark} ), "\n"; |
120
|
|
|
|
|
|
|
} |
121
|
1
|
|
|
|
|
65
|
close $outfile; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
125
|
|
|
|
|
|
|
# load_markers() |
126
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub load_markers { |
129
|
1
|
|
|
1
|
1
|
21
|
my ( $self, $filename ) = @_; |
130
|
1
|
50
|
|
|
|
8
|
my $infile = IO::File->new( $filename, "r" ) |
131
|
|
|
|
|
|
|
or croak "Couldn't open $filename for reading"; |
132
|
1
|
|
|
|
|
94
|
my $markers = $MARKS{ refaddr $self }; |
133
|
1
|
|
|
|
|
2
|
my $mark; |
134
|
1
|
|
|
|
|
12
|
while ( defined( $mark = <$infile> ) ) { |
135
|
5
|
|
|
|
|
7
|
chomp $mark; |
136
|
5
|
|
|
|
|
8
|
my $position = <$infile>; |
137
|
5
|
|
|
|
|
6
|
chomp $position; |
138
|
5
|
|
|
|
|
13
|
$position = pack( "H*", $position ); |
139
|
5
|
|
|
|
|
22
|
$markers->{$mark} = $position; |
140
|
|
|
|
|
|
|
} |
141
|
1
|
|
|
|
|
18
|
close $infile; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
145
|
|
|
|
|
|
|
# DESTROY() |
146
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub DESTROY { |
149
|
5
|
|
|
5
|
|
2917
|
my $self = shift; |
150
|
5
|
|
|
|
|
74
|
delete $MARKS{ refaddr $self }; |
151
|
5
|
|
|
|
|
41
|
delete $REGISTRY{ refaddr $self }; |
152
|
|
|
|
|
|
|
|
153
|
5
|
|
|
|
|
228
|
$self->SUPER::DESTROY; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
157
|
|
|
|
|
|
|
# CLONE() |
158
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub CLONE { |
161
|
0
|
|
|
0
|
|
0
|
for my $old_id ( keys %REGISTRY ) { |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# look under old_id to find the new, cloned reference |
164
|
0
|
|
|
|
|
0
|
my $object = $REGISTRY{$old_id}; |
165
|
0
|
|
|
|
|
0
|
my $new_id = refaddr $object; |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# relocate data |
168
|
0
|
|
|
|
|
0
|
$MARKS{$new_id} = $MARKS{$old_id}; |
169
|
0
|
|
|
|
|
0
|
delete $MARKS{$old_id}; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# update the weak reference to the new, cloned object |
172
|
0
|
|
|
|
|
0
|
weaken( $REGISTRY{$new_id} = $object ); |
173
|
0
|
|
|
|
|
0
|
delete $REGISTRY{$old_id}; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
0
|
|
|
|
|
0
|
return; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
180
|
|
|
|
|
|
|
# _object_count() -- used in test scripts to see if memory is leaking |
181
|
|
|
|
|
|
|
#--------------------------------------------------------------------------# |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
sub _object_count { |
184
|
1
|
|
|
1
|
|
1926
|
return scalar keys %REGISTRY; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
1; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
__END__ |