File Coverage

blib/lib/IO/Framed/Read.pm
Criterion Covered Total %
statement 51 55 92.7
branch 18 24 75.0
condition 4 6 66.6
subroutine 10 11 90.9
pod 0 5 0.0
total 83 101 82.1


line stmt bran cond sub pod time code
1             package IO::Framed::Read;
2              
3 5     5   178786 use strict;
  5         26  
  5         481  
4 5     5   22 use warnings;
  5         9  
  5         98  
5              
6 5     5   1644 use IO::Framed::X ();
  5         14  
  5         1771  
7              
8             sub new {
9 6     6 0 1436 my ( $class, $in_fh, $initial_buffer ) = @_;
10              
11 6 50       23 if ( !defined $initial_buffer ) {
12 6         12 $initial_buffer = q<>;
13             }
14              
15 6         25 my $self = {
16             _in_fh => $in_fh,
17             _read_buffer => $initial_buffer,
18             _bytes_to_read => 0,
19             };
20              
21 6         21 return bless $self, $class;
22             }
23              
24 0     0 0 0 sub get_read_fh { return $_[0]->{'_in_fh'} }
25              
26             #----------------------------------------------------------------------
27             # IO subclass interface
28              
29             sub allow_empty_read {
30 2     2 0 479 my ($self) = @_;
31 2         5 $self->{'_ALLOW_EMPTY_READ'} = 1;
32 2         5 return $self;
33             }
34              
35             sub READ {
36 3     3   810 require IO::SigGuard;
37 3         991 *READ = *IO::SigGuard::sysread;
38 3         15 goto &READ;
39             }
40              
41             #We assume here that whatever read may be incomplete at first
42             #will eventually be repeated so that we can complete it. e.g.:
43             #
44             # - read 4 bytes, receive 1, cache it - return undef
45             # - select()
46             # - read 4 bytes again; since we already have 1 byte, only read 3
47             # … and now we get the remaining 3, so return the buffer.
48             #
49             sub read {
50 10     10 0 1010 my ( $self, $bytes ) = @_;
51              
52 10 50       25 die "I refuse to read zero!" if !$bytes;
53              
54 10 100       30 if ( length $self->{'_read_buffer'} ) {
55 1 50       5 if ( length($self->{'_read_buffer'}) + $self->{'_bytes_to_read'} != $bytes ) {
56 0         0 my $should_be = length($self->{'_read_buffer'}) + $self->{'_bytes_to_read'};
57 0         0 die "Continuation: should want “$should_be” bytes, not $bytes!";
58             }
59             }
60              
61 10 50       19 if ( $bytes > length($self->{'_read_buffer'}) ) {
62 10         21 $bytes -= length($self->{'_read_buffer'});
63              
64 10         27 local $!;
65              
66 10         19 local $self->{'_return'};
67              
68 10         31 $bytes -= $self->_expand_read_buffer( $bytes );
69              
70 8 100       171 return q<> if $self->{'_return'};
71             }
72              
73 7         12 $self->{'_bytes_to_read'} = $bytes;
74              
75 7 100       16 if ($bytes) {
76 2         7 return undef;
77             }
78              
79 5         30 return substr( $self->{'_read_buffer'}, 0, length($self->{'_read_buffer'}), q<> );
80             }
81              
82             sub _expand_read_buffer {
83 14   100 14   156 return $_[0]->can('READ')->( $_[0]->{'_in_fh'}, $_[0]->{'_read_buffer'}, $_[1], length($_[0]->{'_read_buffer'}) ) || do {
84             if ($!) {
85 4     4   1612 if ( !$!{'EAGAIN'} && !$!{'EWOULDBLOCK'}) {
  4         4871  
  4         28  
86             die IO::Framed::X->create( 'ReadError', $! );
87             }
88             }
89             elsif ($_[0]->{'_ALLOW_EMPTY_READ'}) {
90             $_[0]->{'_return'} = 1;
91             0;
92             }
93             else {
94             die IO::Framed::X->create('EmptyRead');
95             }
96             };
97             }
98              
99             sub read_until {
100 5     5 0 54 my ( $self, $seq ) = @_;
101              
102 5 50       17 if ( $self->{'_bytes_to_read'} ) {
103 0         0 die "Don’t call read_until() after an incomplete read()!";
104             }
105              
106 5 50 33     24 die "Missing read-until sequence!" if !defined $seq || !length $seq;
107              
108 5         9 my $at = index( $self->{'_read_buffer'}, $seq );
109              
110 5 100       10 if ($at > -1) {
111 1         6 return substr( $self->{'_read_buffer'}, 0, $at + length($seq), q<> );
112             }
113              
114 4         9 local $self->{'_return'};
115              
116 4         9 $self->_expand_read_buffer( 65536 );
117              
118 3 100       56 return q<> if $self->{'_return'};
119              
120 2         4 $at = index( $self->{'_read_buffer'}, $seq );
121              
122 2 100       6 if ($at > -1) {
123 1         7 return substr( $self->{'_read_buffer'}, 0, $at + length($seq), q<> );
124             }
125              
126 1         6 return undef;
127             }
128              
129             #----------------------------------------------------------------------
130              
131             1;