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   171835 use strict;
  5         30  
  5         163  
4 5     5   26 use warnings;
  5         10  
  5         118  
5              
6 5     5   2004 use IO::Framed::X ();
  5         15  
  5         2009  
7              
8             sub new {
9 6     6 0 1699 my ( $class, $in_fh, $initial_buffer ) = @_;
10              
11 6 50       25 if ( !defined $initial_buffer ) {
12 6         14 $initial_buffer = q<>;
13             }
14              
15 6         24 my $self = {
16             _in_fh => $in_fh,
17             _read_buffer => $initial_buffer,
18             _bytes_to_read => 0,
19             };
20              
21 6         27 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 571 my ($self) = @_;
31 2         5 $self->{'_ALLOW_EMPTY_READ'} = 1;
32 2         7 return $self;
33             }
34              
35             sub READ {
36 3     3   953 require IO::SigGuard;
37 3         1193 *READ = *IO::SigGuard::sysread;
38 3         17 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 1184 my ( $self, $bytes ) = @_;
51              
52 10 50       31 die "I refuse to read zero!" if !$bytes;
53              
54 10 100       36 if ( length $self->{'_read_buffer'} ) {
55 1 50       15 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       31 if ( $bytes > length($self->{'_read_buffer'}) ) {
62 10         16 $bytes -= length($self->{'_read_buffer'});
63              
64 10         35 local $!;
65              
66 10         22 local $self->{'_return'};
67              
68 10         40 $bytes -= $self->_expand_read_buffer( $bytes );
69              
70 8 100       178 return q<> if $self->{'_return'};
71             }
72              
73 7         19 $self->{'_bytes_to_read'} = $bytes;
74              
75 7 100       20 if ($bytes) {
76 2         11 return undef;
77             }
78              
79 5         36 return substr( $self->{'_read_buffer'}, 0, length($self->{'_read_buffer'}), q<> );
80             }
81              
82             sub _expand_read_buffer {
83 14   100 14   98 return $_[0]->can('READ')->( $_[0]->{'_in_fh'}, $_[0]->{'_read_buffer'}, $_[1], length($_[0]->{'_read_buffer'}) ) || do {
84             if ($!) {
85 4     4   1938 if ( !$!{'EAGAIN'} && !$!{'EWOULDBLOCK'}) {
  4         5558  
  4         39  
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 59 my ( $self, $seq ) = @_;
101              
102 5 50       22 if ( $self->{'_bytes_to_read'} ) {
103 0         0 die "Don’t call read_until() after an incomplete read()!";
104             }
105              
106 5 50 33     26 die "Missing read-until sequence!" if !defined $seq || !length $seq;
107              
108 5         12 my $at = index( $self->{'_read_buffer'}, $seq );
109              
110 5 100       13 if ($at > -1) {
111 1         7 return substr( $self->{'_read_buffer'}, 0, $at + length($seq), q<> );
112             }
113              
114 4         8 local $self->{'_return'};
115              
116 4         13 $self->_expand_read_buffer( 65536 );
117              
118 3 100       99 return q<> if $self->{'_return'};
119              
120 2         6 $at = index( $self->{'_read_buffer'}, $seq );
121              
122 2 100       7 if ($at > -1) {
123 1         8 return substr( $self->{'_read_buffer'}, 0, $at + length($seq), q<> );
124             }
125              
126 1         7 return undef;
127             }
128              
129             #----------------------------------------------------------------------
130              
131             1;