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   105477 use strict;
  24         164  
  24         631  
4 24     24   9215 use Symbol;
  24         15383  
  24         1524  
5 24     24   8184 use FileHandle;
  24         166579  
  24         178  
6 24     24   7081 use Exporter;
  24         54  
  24         990  
7 24     24   134 use Scalar::Util qw( weaken );
  24         47  
  24         2619  
8              
9 24     24   404 use 5.005;
  24         78  
10              
11 24     24   135 use vars qw( @ISA $VERSION $AUTOLOAD @EXPORT @EXPORT_OK );
  24         49  
  24         3621  
12              
13             @ISA = qw( Exporter FileHandle );
14              
15             $VERSION = sprintf "%d.%02d%02d", q/0.16.33/ =~ /(\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   154 no strict 'refs'; ## no critic (strict)
  24         48  
  24         17589  
27              
28 168 50   168 0 427 my $class = shift or return;
29 168   100     418 my $seen = shift || {};
30              
31             # Locate methods in this class
32 168         233 my $symtab = \%{"$class\::"};
  168         425  
33 168         1612 my @names = keys %$symtab;
34 168         956 for my $method (keys %$symtab)
35             {
36 5760         9623 my $fullname = "$class\::$method";
37              
38 5760 100       14567 next unless defined &$fullname;
39 4224 100       5015 next if defined &{__PACKAGE__ . "::$method"};
  4224         13718  
40 1704 100       2975 next if $method eq 'import';
41              
42 1608 50       2626 unless ($seen->{$method})
43             {
44 1608         2595 $seen->{$method} = $fullname;
45              
46 1608         5648 *{$method} = sub
47             {
48 182     182   18508 my $self = $_[0];
49              
50 182 100       473 if (ref $self eq __PACKAGE__)
51             {
52 180         312 shift @_;
53 180         375 my $super = "SUPER::$method";
54 180         2090 $self->$super(@_);
55             }
56             else
57             {
58 2         8 $method = "FileHandle::$method";
59 2         12 &$method(@_);
60             }
61 1608         6106 };
62             }
63             }
64              
65             # Traverse parent classes of this one
66 168         428 my @ISA = @{"$class\::ISA"};
  168         575  
67 168         764 for my $class (@ISA)
68             {
69 144         799 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 15538 my $class = shift;
86              
87 48         80 my $self;
88              
89 48 100 100     385 if (defined $_[0] && defined fileno $_[0])
90             {
91 12         24 $self = shift;
92             }
93             else
94             {
95 36         231 $self = $class->SUPER::new(@_);
96 36 50       3578 return undef unless defined $self; ## no critic (ProhibitExplicitReturnUndef)
97             }
98              
99 48         230 my $values =
100             {
101             'fh' => $self,
102             'eof_called' => 0,
103             'filehandle_unget_buffer' => '',
104             };
105              
106 48         226 weaken($values->{'fh'});
107            
108 48         366 tie *$self, "${class}::Tie", $values;
109              
110 48         116 bless $self, $class;
111 48         131 return $self;
112             }
113              
114             #-------------------------------------------------------------------------------
115              
116             sub new_from_fd
117             {
118 1     1 1 43 my $class = shift;
119              
120 1         2 my $self;
121              
122             # if (defined $_[0] && defined fileno $_[0])
123             # {
124             # $self = shift;
125             # }
126             # else
127             {
128 1         1 $self = $class->SUPER::new_from_fd(@_);
  1         8  
129 1 50       98 return undef unless defined $self; ## no critic (ProhibitExplicitReturnUndef)
130             }
131              
132 1         4 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         5 tie *$self, "${class}::Tie", $values;
142              
143 1         2 bless $self, $class;
144 1         3 return $self;
145             }
146              
147             #-------------------------------------------------------------------------------
148              
149             sub ungetc
150             {
151 23     23 1 68 my $self = shift;
152 23         24 my $ord = shift;
153              
154 23         48 substr(tied(*$self)->{'filehandle_unget_buffer'},0,0) = chr($ord);
155             }
156              
157             #-------------------------------------------------------------------------------
158              
159             sub ungets
160             {
161 11     11 1 2223 my $self = shift;
162 11         18 my $string = shift;
163              
164 11         41 substr(tied(*$self)->{'filehandle_unget_buffer'},0,0) = $string;
165             }
166              
167             #-------------------------------------------------------------------------------
168              
169             sub buffer
170             {
171 3     3 1 6 my $self = shift;
172              
173 3 100       7 tied(*$self)->{'filehandle_unget_buffer'} = shift if @_;
174 3         19 return tied(*$self)->{'filehandle_unget_buffer'};
175             }
176              
177             #-------------------------------------------------------------------------------
178              
179             sub input_record_separator
180             {
181 3     3 1 571 my $self = shift;
182              
183 3 50       7 if(@_)
184             {
185 3         7 tied(*$self)->{'input_record_separator'} = shift;
186             }
187              
188 3 50       8 return undef unless exists tied(*$self)->{'input_record_separator'}; ## no critic (ProhibitExplicitReturnUndef)
189 3         5 return tied(*$self)->{'input_record_separator'};
190             }
191              
192             #-------------------------------------------------------------------------------
193              
194             sub clear_input_record_separator
195             {
196 1     1 1 5 my $self = shift;
197              
198 1         3 delete tied(*$self)->{'input_record_separator'};
199             }
200              
201             ###############################################################################
202              
203             package FileHandle::Unget::Tie;
204              
205 24     24   164 use strict;
  24         47  
  24         559  
206 24     24   130 use FileHandle;
  24         64  
  24         105  
207 24     24   19228 use bytes;
  24         318  
  24         110  
208              
209 24     24   778 use 5.000;
  24         81  
210              
211 24     24   117 use vars qw( $VERSION $AUTOLOAD @ISA );
  24         47  
  24         2914  
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   14320 my $name = $AUTOLOAD;
231 59         480 $name =~ s/.*://;
232              
233 59 50       308 die "Unhandled function $name!" unless exists $tie_mapping{$name};
234              
235 59         175 my $sub = $tie_mapping{$name};
236              
237             # Alias the anonymous subroutine to the name of the sub we want ...
238 24     24   146 no strict 'refs'; ## no critic (strict)
  24         37  
  24         39698  
239 59         243 *{$name} = sub
240             {
241 143     143   12385 my $self = shift;
242              
243 143 100       595 if (defined &$sub)
244             {
245 92         297 &$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         105 local $^W = 0;
  51         252  
255 51         90 untie *{$self->{'fh'}};
  51         348  
256             }
257              
258 51         298 $self->{'fh'}->$sub(@_);
259              
260 51         5299 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  51         299  
261             }
262 59         334 };
263              
264             # ... and go to it.
265 59         242 goto &$name;
266             }
267              
268             #-------------------------------------------------------------------------------
269              
270             sub DESTROY
271       0     {
272             }
273              
274             #-------------------------------------------------------------------------------
275              
276             sub TIEHANDLE
277             {
278 192     192   336 my $class = shift;
279 192         268 my $self = shift;
280              
281 192         302 bless($self, $class);
282              
283 192         785 return $self;
284             }
285              
286             #-------------------------------------------------------------------------------
287              
288             sub binmode
289             {
290 2     2   4 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       63 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         12 local $^W = 0;
  2         10  
301 2         6 untie *{$self->{'fh'}};
  2         12  
302             }
303              
304 2 50       17 if (@_)
305             {
306 0         0 binmode $self->{'fh'}, @_;
307             }
308             else
309             {
310 2         11 binmode $self->{'fh'};
311             }
312              
313 2         5 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  2         7  
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         2 local $^W = 0;
  1         3  
328 1         2 untie *{$self->{'fh'}};
  1         5  
329             }
330              
331 1         5 my $fileno = fileno $self->{'fh'};
332              
333 1         1 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   140 if (wantarray)
343             {
344 4         18 goto &getlines;
345             }
346             else
347             {
348 57         182 goto &getline;
349             }
350             }
351              
352             #-------------------------------------------------------------------------------
353              
354             sub getline
355             {
356 57     57   96 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         77 local $^W = 0;
  57         181  
364 57         90 untie *{$self->{'fh'}};
  57         282  
365             }
366              
367 57         91 my $line;
368              
369             local $/ = $self->{'input_record_separator'}
370 57 100       158 if exists $self->{'input_record_separator'};
371 57         105 my $input_record_separator = $/;
372              
373 57 100 100     485 if (defined $input_record_separator &&
    100          
374             $self->{'filehandle_unget_buffer'} =~ /(.*?$input_record_separator)/)
375             {
376 9         20 $line = $1;
377 9         24 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         16 $line = $self->{'filehandle_unget_buffer'};
388 5         21 $self->{'filehandle_unget_buffer'} = '';
389 5         32 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     387 @other_lines = () if @other_lines && !defined($other_lines[0]);
394              
395 5 50 66     57 if ($line eq '' && !@other_lines)
396             {
397 0         0 $line = undef;
398             }
399             else
400             {
401 5         19 $line .= join('', @other_lines);
402             }
403             }
404             else
405             {
406 43         85 $line = $self->{'filehandle_unget_buffer'};
407 43         75 $self->{'filehandle_unget_buffer'} = '';
408 43         128 my $templine = $self->{'fh'}->getline(@_);
409              
410 43 100 100     1415 if ($line eq '' && !defined $templine)
    50          
411             {
412 2         5 $line = undef;
413             }
414             elsif (defined $templine)
415             {
416 41         108 $line .= $templine;
417             }
418             }
419              
420 57         77 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  57         210  
421              
422 57         215 return $line;
423             }
424              
425             #-------------------------------------------------------------------------------
426              
427             sub getlines
428             {
429 4     4   8 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         9 local $^W = 0;
  4         14  
437 4         8 untie *{$self->{'fh'}};
  4         16  
438             }
439              
440 4         8 my @buffer_lines;
441              
442             local $/ = $self->{'input_record_separator'}
443 4 50       14 if exists $self->{'input_record_separator'};
444 4         11 my $input_record_separator = $/;
445              
446 4 50       15 if (defined $input_record_separator)
447             {
448 4         58 $self->{'filehandle_unget_buffer'} =~
449 0         0 s/^(.*$input_record_separator)/push @buffer_lines, $1;''/mge;
  0         0  
450              
451 4         22 my @other_lines = $self->{'fh'}->getlines(@_);
452              
453 4 100       210 if (@other_lines)
454             {
455 3 50       9 if (defined $other_lines[0])
456             {
457 3         11 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         11 $self->{'filehandle_unget_buffer'} = '';
469              
470 4         11 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         7 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  4         16  
494              
495 4         17 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   18 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         20 local $^W = 0;
  10         34  
542 10         18 untie *{$self->{'fh'}};
  10         47  
543             }
544              
545 10         22 my $scalar = \$_[0];
546 10         18 my $length = $_[1];
547 10         14 my $offset = $_[2];
548              
549 10         16 my $num_bytes_read = 0;
550              
551 10 100       30 if ($self->{'filehandle_unget_buffer'} ne '')
552             {
553 3         8 my $read_string = substr($self->{'filehandle_unget_buffer'},0,$length);
554 3         8 substr($self->{'filehandle_unget_buffer'},0,$length) = '';
555              
556 3         4 my $num_bytes_buffer = length $read_string;
557              
558             # Try to read the rest
559 3 50       10 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       6 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         6 $$scalar = $read_string;
573             }
574              
575 3         6 $num_bytes_read += $num_bytes_buffer;
576             }
577             else
578             {
579 7 100       19 if (defined $_[2])
580             {
581 3         41 $num_bytes_read = read($self->{'fh'},$_[0],$_[1],$_[2]);
582             }
583             else
584             {
585 4         60 $num_bytes_read = read($self->{'fh'},$_[0],$_[1]);
586             }
587             }
588              
589 10         24 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  10         39  
590              
591 10         32 return $num_bytes_read;
592             }
593              
594             #-------------------------------------------------------------------------------
595              
596             sub seek
597             {
598 3     3   4 my $self = shift;
599 3         5 my $position = $_[0];
600 3         4 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         4 local $^W = 0;
  3         9  
608 3         4 untie *{$self->{'fh'}};
  3         14  
609             }
610              
611 3 50 66     14 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         4 my $status;
618              
619             # First try to seek using the built-in seek
620 3 50       31 if (seek($self->{'fh'},$position,$whence))
621             {
622 3         9 $self->{'filehandle_unget_buffer'} = '';
623 3         4 $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         4 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  3         12  
656              
657 3         8 return $status;
658             }
659              
660             #-------------------------------------------------------------------------------
661              
662             sub tell
663             {
664 11     11   18 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         14 local $^W = 0;
  11         33  
672 11         17 untie *{$self->{'fh'}};
  11         45  
673             }
674              
675 11         32 my $file_position = tell $self->{'fh'};
676              
677 11 50       32 if ($file_position == -1)
678             {
679 0         0 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  0         0  
680 0         0 return -1;
681             }
682              
683 11         22 $file_position -= length($self->{'filehandle_unget_buffer'});
684              
685 11         16 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  11         30  
686              
687 11         48 return $file_position;
688             }
689              
690             #-------------------------------------------------------------------------------
691              
692             sub eof
693             {
694 4     4   14 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         12 local $^W = 0;
  4         31  
702 4         11 untie *{$self->{'fh'}};
  4         40  
703             }
704              
705 4         17 my $eof;
706              
707 4 50       29 if ($self->{'filehandle_unget_buffer'} ne '')
708             {
709 0         0 $eof = 0;
710             }
711             else
712             {
713 4         41 $eof = $self->{'fh'}->eof();
714             }
715              
716 4         3079 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  4         38  
717              
718 4         31 $self->{'eof_called'} = 1;
719              
720 4         23 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__