File Coverage

blib/lib/FileHandle/Unget.pm
Criterion Covered Total %
statement 253 300 84.3
branch 53 90 58.8
condition 17 26 65.3
subroutine 35 39 89.7
pod 7 8 87.5
total 365 463 78.8


line stmt bran cond sub pod time code
1             package FileHandle::Unget;
2              
3 24     24   122588 use strict;
  24         161  
  24         587  
4 24     24   8882 use Symbol;
  24         14183  
  24         1432  
5 24     24   8395 use FileHandle;
  24         165408  
  24         187  
6 24     24   6761 use Exporter;
  24         55  
  24         926  
7 24     24   131 use Scalar::Util qw( weaken );
  24         42  
  24         2447  
8              
9 24     24   386 use 5.005;
  24         106  
10              
11 24     24   116 use vars qw( @ISA $VERSION $AUTOLOAD @EXPORT @EXPORT_OK );
  24         49  
  24         3520  
12              
13             @ISA = qw( Exporter FileHandle );
14              
15             $VERSION = sprintf "%d.%02d%02d", q/0.16.34/ =~ /(\d+)/g;
16              
17             @EXPORT = @FileHandle::EXPORT;
18             @EXPORT_OK = @FileHandle::EXPORT_OK;
19              
20             # Based on dump_methods from this most helpful post by MJD:
21             # http://groups.google.com/groups?selm=20020621182734.15920.qmail%40plover.com
22             # We can't just use AUTOLOAD because AUTOLOAD is not called for inherited
23             # methods
24             sub wrap_methods
25             {
26 24     24   147 no strict 'refs'; ## no critic (strict)
  24         44  
  24         17088  
27              
28 168 50   168 0 459 my $class = shift or return;
29 168   100     429 my $seen = shift || {};
30              
31             # Locate methods in this class
32 168         203 my $symtab = \%{"$class\::"};
  168         434  
33 168         1626 my @names = keys %$symtab;
34 168         981 for my $method (keys %$symtab)
35             {
36 5760         9475 my $fullname = "$class\::$method";
37              
38 5760 100       14278 next unless defined &$fullname;
39 4224 100       4908 next if defined &{__PACKAGE__ . "::$method"};
  4224         14134  
40 1704 100       2897 next if $method eq 'import';
41              
42 1608 50       2597 unless ($seen->{$method})
43             {
44 1608         2422 $seen->{$method} = $fullname;
45              
46 1608         5577 *{$method} = sub
47             {
48 182     182   17809 my $self = $_[0];
49              
50 182 100       520 if (ref $self eq __PACKAGE__)
51             {
52 180         293 shift @_;
53 180         641 my $super = "SUPER::$method";
54 180         2346 $self->$super(@_);
55             }
56             else
57             {
58 2         6 $method = "FileHandle::$method";
59 2         12 &$method(@_);
60             }
61 1608         5657 };
62             }
63             }
64              
65             # Traverse parent classes of this one
66 168         410 my @ISA = @{"$class\::ISA"};
  168         577  
67 168         779 for my $class (@ISA)
68             {
69 144         802 wrap_methods($class, $seen);
70             }
71             }
72              
73             wrap_methods('FileHandle');
74              
75             #-------------------------------------------------------------------------------
76              
77             sub DESTROY
78       0     {
79             }
80              
81             #-------------------------------------------------------------------------------
82              
83             sub new
84             {
85 48     48 1 16258 my $class = shift;
86              
87 48         92 my $self;
88              
89 48 100 100     426 if (defined $_[0] && defined fileno $_[0])
90             {
91 12         26 $self = shift;
92             }
93             else
94             {
95 36         260 $self = $class->SUPER::new(@_);
96 36 50       3409 return undef unless defined $self; ## no critic (ProhibitExplicitReturnUndef)
97             }
98              
99 48         233 my $values =
100             {
101             'fh' => $self,
102             'eof_called' => 0,
103             'filehandle_unget_buffer' => '',
104             };
105              
106 48         243 weaken($values->{'fh'});
107            
108 48         406 tie *$self, "${class}::Tie", $values;
109              
110 48         136 bless $self, $class;
111 48         164 return $self;
112             }
113              
114             #-------------------------------------------------------------------------------
115              
116             sub new_from_fd
117             {
118 1     1 1 46 my $class = shift;
119              
120 1         3 my $self;
121              
122             # if (defined $_[0] && defined fileno $_[0])
123             # {
124             # $self = shift;
125             # }
126             # else
127             {
128 1         3 $self = $class->SUPER::new_from_fd(@_);
  1         10  
129 1 50       133 return undef unless defined $self; ## no critic (ProhibitExplicitReturnUndef)
130             }
131              
132 1         6 my $values =
133             {
134             'fh' => $self,
135             'eof_called' => 0,
136             'filehandle_unget_buffer' => '',
137             };
138              
139 1         6 weaken($values->{'fh'});
140            
141 1         6 tie *$self, "${class}::Tie", $values;
142              
143 1         4 bless $self, $class;
144 1         3 return $self;
145             }
146              
147             #-------------------------------------------------------------------------------
148              
149             sub ungetc
150             {
151 23     23 1 92 my $self = shift;
152 23         31 my $ord = shift;
153              
154 23         57 substr(tied(*$self)->{'filehandle_unget_buffer'},0,0) = chr($ord);
155             }
156              
157             #-------------------------------------------------------------------------------
158              
159             sub ungets
160             {
161 11     11 1 1923 my $self = shift;
162 11         24 my $string = shift;
163              
164 11         43 substr(tied(*$self)->{'filehandle_unget_buffer'},0,0) = $string;
165             }
166              
167             #-------------------------------------------------------------------------------
168              
169             sub buffer
170             {
171 3     3 1 11 my $self = shift;
172              
173 3 100       11 tied(*$self)->{'filehandle_unget_buffer'} = shift if @_;
174 3         24 return tied(*$self)->{'filehandle_unget_buffer'};
175             }
176              
177             #-------------------------------------------------------------------------------
178              
179             sub input_record_separator
180             {
181 3     3 1 393 my $self = shift;
182              
183 3 50       6 if(@_)
184             {
185 3         6 tied(*$self)->{'input_record_separator'} = shift;
186             }
187              
188 3 50       6 return undef unless exists tied(*$self)->{'input_record_separator'}; ## no critic (ProhibitExplicitReturnUndef)
189 3         4 return tied(*$self)->{'input_record_separator'};
190             }
191              
192             #-------------------------------------------------------------------------------
193              
194             sub clear_input_record_separator
195             {
196 1     1 1 4 my $self = shift;
197              
198 1         2 delete tied(*$self)->{'input_record_separator'};
199             }
200              
201             ###############################################################################
202              
203             package FileHandle::Unget::Tie;
204              
205 24     24   196 use strict;
  24         54  
  24         577  
206 24     24   129 use FileHandle;
  24         60  
  24         103  
207 24     24   20001 use bytes;
  24         289  
  24         101  
208              
209 24     24   763 use 5.000;
  24         78  
210              
211 24     24   118 use vars qw( $VERSION $AUTOLOAD @ISA );
  24         59  
  24         2821  
212              
213             @ISA = qw( IO::Handle );
214              
215             $VERSION = '0.10';
216              
217             #-------------------------------------------------------------------------------
218              
219             my %tie_mapping = (
220             PRINT => 'print', PRINTF => 'printf', WRITE => 'syswrite',
221             READLINE => 'getline_wrapper', GETC => 'getc', READ => 'read', CLOSE => 'close',
222             BINMODE => 'binmode', OPEN => 'open', EOF => 'eof', FILENO => 'fileno',
223             SEEK => 'seek', TELL => 'tell', FETCH => 'fetch',
224             );
225              
226             #-------------------------------------------------------------------------------
227              
228             sub AUTOLOAD
229             {
230 59     59   15447 my $name = $AUTOLOAD;
231 59         532 $name =~ s/.*://;
232              
233 59 50       330 die "Unhandled function $name!" unless exists $tie_mapping{$name};
234              
235 59         217 my $sub = $tie_mapping{$name};
236              
237             # Alias the anonymous subroutine to the name of the sub we want ...
238 24     24   135 no strict 'refs'; ## no critic (strict)
  24         57  
  24         38022  
239 59         295 *{$name} = sub
240             {
241 143     143   10550 my $self = shift;
242              
243 143 100       627 if (defined &$sub)
244             {
245 92         334 &$sub($self,@_);
246             }
247             else
248             {
249             # Prevent recursion
250             # Temporarily disable warnings so that we don't get "untie attempted
251             # while 1 inner references still exist". Not sure what's the "right
252             # thing" to do here.
253             {
254 51         118 local $^W = 0;
  51         305  
255 51         130 untie *{$self->{'fh'}};
  51         328  
256             }
257              
258 51         383 $self->{'fh'}->$sub(@_);
259              
260 51         1412 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  51         312  
261             }
262 59         382 };
263              
264             # ... and go to it.
265 59         275 goto &$name;
266             }
267              
268             #-------------------------------------------------------------------------------
269              
270             sub DESTROY
271       0     {
272             }
273              
274             #-------------------------------------------------------------------------------
275              
276             sub TIEHANDLE
277             {
278 192     192   400 my $class = shift;
279 192         289 my $self = shift;
280              
281 192         330 bless($self, $class);
282              
283 192         859 return $self;
284             }
285              
286             #-------------------------------------------------------------------------------
287              
288             sub binmode
289             {
290 2     2   6 my $self = shift;
291              
292             warn "Under windows, calling binmode after eof exposes a bug that exists in some versions of Perl.\n"
293 2 100       65 if $self->{'eof_called'};
294              
295             # Prevent recursion
296             # Temporarily disable warnings so that we don't get "untie attempted
297             # while 1 inner references still exist". Not sure what's the "right
298             # thing" to do here.
299             {
300 2         8 local $^W = 0;
  2         12  
301 2         6 untie *{$self->{'fh'}};
  2         14  
302             }
303              
304 2 50       10 if (@_)
305             {
306 0         0 binmode $self->{'fh'}, @_;
307             }
308             else
309             {
310 2         12 binmode $self->{'fh'};
311             }
312              
313 2         6 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  2         14  
314             }
315              
316             #-------------------------------------------------------------------------------
317              
318             sub fileno
319             {
320 1     1   2 my $self = shift;
321              
322             # Prevent recursion
323             # Temporarily disable warnings so that we don't get "untie attempted
324             # while 1 inner references still exist". Not sure what's the "right
325             # thing" to do here.
326             {
327 1         9 local $^W = 0;
  1         4  
328 1         2 untie *{$self->{'fh'}};
  1         6  
329             }
330              
331 1         2 my $fileno = fileno $self->{'fh'};
332              
333 1         2 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  1         3  
334              
335 1         8 return $fileno;
336             }
337              
338             #-------------------------------------------------------------------------------
339              
340             sub getline_wrapper
341             {
342 61 100   61   143 if (wantarray)
343             {
344 4         19 goto &getlines;
345             }
346             else
347             {
348 57         211 goto &getline;
349             }
350             }
351              
352             #-------------------------------------------------------------------------------
353              
354             sub getline
355             {
356 57     57   99 my $self = shift;
357              
358             # Prevent recursion
359             # Temporarily disable warnings so that we don't get "untie attempted
360             # while 1 inner references still exist". Not sure what's the "right
361             # thing" to do here.
362             {
363 57         87 local $^W = 0;
  57         179  
364 57         91 untie *{$self->{'fh'}};
  57         283  
365             }
366              
367 57         98 my $line;
368              
369             local $/ = $self->{'input_record_separator'}
370 57 100       161 if exists $self->{'input_record_separator'};
371 57         116 my $input_record_separator = $/;
372              
373 57 100 100     550 if (defined $input_record_separator &&
    100          
374             $self->{'filehandle_unget_buffer'} =~ /(.*?$input_record_separator)/)
375             {
376 9         24 $line = $1;
377 9         23 substr($self->{'filehandle_unget_buffer'},0,length $line) = '';
378             }
379             # My best guess at a fix for failures like these:
380             # http://www.cpantesters.org/cpan/report/2185d342-b14c-11e4-9727-fcccf9ba27bb
381             # http://www.cpantesters.org/cpan/report/74a6f9b6-95db-11e4-8169-9f55a5948d86
382             # It seems like even though $/ == undef, we're not reading all the rest of
383             # the file. Unfortunately I can't repro this, so I'll change it and see if
384             # the CPAN-Testers tests start passing.
385             elsif (!defined($input_record_separator))
386             {
387 5         15 $line = $self->{'filehandle_unget_buffer'};
388 5         13 $self->{'filehandle_unget_buffer'} = '';
389 5         29 my @other_lines = $self->{'fh'}->getlines(@_);
390              
391             # Not sure if this is necessary. The code in getlines() below seems to
392             # suggest so.
393 5 50 33     369 @other_lines = () if @other_lines && !defined($other_lines[0]);
394              
395 5 50 66     40 if ($line eq '' && !@other_lines)
396             {
397 0         0 $line = undef;
398             }
399             else
400             {
401 5         24 $line .= join('', @other_lines);
402             }
403             }
404             else
405             {
406 43         111 $line = $self->{'filehandle_unget_buffer'};
407 43         77 $self->{'filehandle_unget_buffer'} = '';
408 43         132 my $templine = $self->{'fh'}->getline(@_);
409              
410 43 100 100     1562 if ($line eq '' && !defined $templine)
    50          
411             {
412 2         5 $line = undef;
413             }
414             elsif (defined $templine)
415             {
416 41         120 $line .= $templine;
417             }
418             }
419              
420 57         99 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  57         218  
421              
422 57         243 return $line;
423             }
424              
425             #-------------------------------------------------------------------------------
426              
427             sub getlines
428             {
429 4     4   11 my $self = shift;
430              
431             # Prevent recursion
432             # Temporarily disable warnings so that we don't get "untie attempted
433             # while 1 inner references still exist". Not sure what's the "right
434             # thing" to do here.
435             {
436 4         11 local $^W = 0;
  4         17  
437 4         10 untie *{$self->{'fh'}};
  4         20  
438             }
439              
440 4         11 my @buffer_lines;
441              
442             local $/ = $self->{'input_record_separator'}
443 4 50       17 if exists $self->{'input_record_separator'};
444 4         12 my $input_record_separator = $/;
445              
446 4 50       19 if (defined $input_record_separator)
447             {
448 4         63 $self->{'filehandle_unget_buffer'} =~
449 0         0 s/^(.*$input_record_separator)/push @buffer_lines, $1;''/mge;
  0         0  
450              
451 4         28 my @other_lines = $self->{'fh'}->getlines(@_);
452              
453 4 100       266 if (@other_lines)
454             {
455 3 50       13 if (defined $other_lines[0])
456             {
457 3         12 substr($other_lines[0],0,0) = $self->{'filehandle_unget_buffer'};
458             }
459             }
460             else
461             {
462 1 50       4 if ($self->{'filehandle_unget_buffer'} ne '')
463             {
464 0         0 unshift @other_lines, $self->{'filehandle_unget_buffer'};
465             }
466             }
467              
468 4         14 $self->{'filehandle_unget_buffer'} = '';
469              
470 4         18 push @buffer_lines, @other_lines;
471             }
472             else
473             {
474 0         0 $buffer_lines[0] = $self->{'filehandle_unget_buffer'};
475 0         0 $self->{'filehandle_unget_buffer'} = '';
476             # Not sure why this isn't working for some platforms. If $/ is undef, then
477             # all the lines should be in [0].
478             # my $templine = ($self->{'fh'}->getlines(@_))[0];
479 0         0 my @other_lines = $self->{'fh'}->getlines(@_);
480              
481 0 0 0     0 if ($buffer_lines[0] eq '' && !defined $other_lines[0])
482             {
483             # Should this really be "(undef)" and not just "undef"? Leaving it for
484             # now, to avoid changing the API until I know the answer.
485 0         0 $buffer_lines[0] = undef;
486             }
487             else
488             {
489 0         0 $buffer_lines[0] .= join('', @other_lines);
490             }
491             }
492              
493 4         10 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  4         20  
494              
495 4         24 return @buffer_lines;
496             }
497              
498             #-------------------------------------------------------------------------------
499              
500             sub getc
501             {
502 0     0   0 my $self = shift;
503              
504             # Prevent recursion
505             # Temporarily disable warnings so that we don't get "untie attempted
506             # while 1 inner references still exist". Not sure what's the "right
507             # thing" to do here.
508             {
509 0         0 local $^W = 0;
  0         0  
510 0         0 untie *{$self->{'fh'}};
  0         0  
511             }
512              
513 0         0 my $char;
514              
515 0 0       0 if ($self->{'filehandle_unget_buffer'} ne '')
516             {
517 0         0 $char = substr($self->{'filehandle_unget_buffer'},0,1);
518 0         0 substr($self->{'filehandle_unget_buffer'},0,1) = '';
519             }
520             else
521             {
522 0         0 $char = $self->{'fh'}->getc(@_);
523             }
524              
525 0         0 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  0         0  
526              
527 0         0 return $char;
528             }
529              
530             #-------------------------------------------------------------------------------
531              
532             sub read
533             {
534 10     10   24 my $self = shift;
535              
536             # Prevent recursion
537             # Temporarily disable warnings so that we don't get "untie attempted
538             # while 1 inner references still exist". Not sure what's the "right
539             # thing" to do here.
540             {
541 10         22 local $^W = 0;
  10         36  
542 10         21 untie *{$self->{'fh'}};
  10         57  
543             }
544              
545 10         24 my $scalar = \$_[0];
546 10         20 my $length = $_[1];
547 10         17 my $offset = $_[2];
548              
549 10         20 my $num_bytes_read = 0;
550              
551 10 100       36 if ($self->{'filehandle_unget_buffer'} ne '')
552             {
553 3         6 my $read_string = substr($self->{'filehandle_unget_buffer'},0,$length);
554 3         6 substr($self->{'filehandle_unget_buffer'},0,$length) = '';
555              
556 3         6 my $num_bytes_buffer = length $read_string;
557              
558             # Try to read the rest
559 3 50       7 if (length($read_string) < $length)
560             {
561 0         0 $num_bytes_read = read($self->{'fh'}, $read_string,
562             $length - $num_bytes_buffer, $num_bytes_buffer);
563             }
564              
565 3 50       9 if (defined $offset)
566             {
567 0 0       0 $$scalar = '' unless defined $$scalar;
568 0         0 substr($$scalar,$offset) = $read_string;
569             }
570             else
571             {
572 3         5 $$scalar = $read_string;
573             }
574              
575 3         4 $num_bytes_read += $num_bytes_buffer;
576             }
577             else
578             {
579 7 100       22 if (defined $_[2])
580             {
581 3         39 $num_bytes_read = read($self->{'fh'},$_[0],$_[1],$_[2]);
582             }
583             else
584             {
585 4         66 $num_bytes_read = read($self->{'fh'},$_[0],$_[1]);
586             }
587             }
588              
589 10         25 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  10         42  
590              
591 10         39 return $num_bytes_read;
592             }
593              
594             #-------------------------------------------------------------------------------
595              
596             sub seek
597             {
598 3     3   4 my $self = shift;
599 3         7 my $position = $_[0];
600 3         5 my $whence = $_[1];
601              
602             # Prevent recursion
603             # Temporarily disable warnings so that we don't get "untie attempted
604             # while 1 inner references still exist". Not sure what's the "right
605             # thing" to do here.
606             {
607 3         6 local $^W = 0;
  3         12  
608 3         6 untie *{$self->{'fh'}};
  3         20  
609             }
610              
611 3 50 66     17 if($whence != 0 && $whence != 1 && $whence != 2)
      33        
612             {
613 0         0 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  0         0  
614 0         0 return 0;
615             }
616              
617 3         7 my $status;
618              
619             # First try to seek using the built-in seek
620 3 50       35 if (seek($self->{'fh'},$position,$whence))
621             {
622 3         11 $self->{'filehandle_unget_buffer'} = '';
623 3         5 $status = 1;
624             }
625             else
626             {
627 0         0 my $absolute_position;
628              
629 0 0       0 $absolute_position = $position if $whence == 0;
630 0 0       0 $absolute_position = $self->tell + $position if $whence == 1;
631 0 0       0 $absolute_position = -s $self->{'fh'} + $position if $whence == 2;
632              
633 0 0       0 if ($absolute_position <= tell $self->{'fh'})
634             {
635 0 0       0 if ($absolute_position >= $self->tell)
636             {
637 0         0 substr($self->{'filehandle_unget_buffer'}, 0,
638             $absolute_position - $self->tell) = '';
639 0         0 $status = 1;
640             }
641             else
642             {
643             # Can't seek backward!
644 0         0 $status = 0;
645             }
646             }
647             else
648             {
649             # Shouldn't the built-in seek handle this?!
650 0         0 warn "Seeking forward is not yet implemented in " . __PACKAGE__ . "\n";
651 0         0 $status = 0;
652             }
653             }
654              
655 3         5 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  3         15  
656              
657 3         11 return $status;
658             }
659              
660             #-------------------------------------------------------------------------------
661              
662             sub tell
663             {
664 11     11   25 my $self = shift;
665              
666             # Prevent recursion
667             # Temporarily disable warnings so that we don't get "untie attempted
668             # while 1 inner references still exist". Not sure what's the "right
669             # thing" to do here.
670             {
671 11         18 local $^W = 0;
  11         41  
672 11         20 untie *{$self->{'fh'}};
  11         55  
673             }
674              
675 11         33 my $file_position = tell $self->{'fh'};
676              
677 11 50       34 if ($file_position == -1)
678             {
679 0         0 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  0         0  
680 0         0 return -1;
681             }
682              
683 11         25 $file_position -= length($self->{'filehandle_unget_buffer'});
684              
685 11         18 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  11         34  
686              
687 11         46 return $file_position;
688             }
689              
690             #-------------------------------------------------------------------------------
691              
692             sub eof
693             {
694 4     4   16 my $self = shift;
695              
696             # Prevent recursion
697             # Temporarily disable warnings so that we don't get "untie attempted
698             # while 1 inner references still exist". Not sure what's the "right
699             # thing" to do here.
700             {
701 4         11 local $^W = 0;
  4         26  
702 4         11 untie *{$self->{'fh'}};
  4         44  
703             }
704              
705 4         14 my $eof;
706              
707 4 50       57 if ($self->{'filehandle_unget_buffer'} ne '')
708             {
709 0         0 $eof = 0;
710             }
711             else
712             {
713 4         52 $eof = $self->{'fh'}->eof();
714             }
715              
716 4         2673 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  4         47  
717              
718 4         45 $self->{'eof_called'} = 1;
719              
720 4         33 return $eof;
721             }
722              
723             #-------------------------------------------------------------------------------
724              
725             sub fetch
726             {
727 0     0     my $self = shift;
728 0           return $self;
729             }
730              
731             1;
732              
733             __END__