File Coverage

blib/lib/FileHandle/Unget.pm
Criterion Covered Total %
statement 255 304 83.8
branch 53 90 58.8
condition 17 26 65.3
subroutine 35 39 89.7
pod 7 8 87.5
total 367 467 78.5


line stmt bran cond sub pod time code
1             package FileHandle::Unget;
2              
3 23     23   30624 use strict;
  23         152  
  23         704  
4 23     23   10362 use Symbol;
  23         16500  
  23         1610  
5 23     23   10907 use FileHandle;
  23         183134  
  23         141  
6 23     23   7454 use Exporter;
  23         46  
  23         953  
7 23     23   127 use Scalar::Util qw( weaken );
  23         42  
  23         2082  
8              
9 23     23   516 use 5.005;
  23         65  
  23         982  
10              
11 23     23   104 use vars qw( @ISA $VERSION $AUTOLOAD @EXPORT @EXPORT_OK );
  23         38  
  23         3212  
12              
13             @ISA = qw( Exporter FileHandle );
14              
15             $VERSION = sprintf "%d.%02d%02d", q/0.16.28/ =~ /(\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 23     23   112 no strict 'refs';
  23         29  
  23         16959  
27              
28 161 50   161 0 406 my $class = shift or return;
29 161   100     356 my $seen = shift || {};
30              
31             # Locate methods in this class
32 161         154 my $symtab = \%{"$class\::"};
  161         639  
33 161         2204 my @names = keys %$symtab;
34 161         833 for my $method (keys %$symtab)
35             {
36 5543         5924 my $fullname = "$class\::$method";
37              
38 5543 100       13552 next unless defined &$fullname;
39 4048 100       3142 next if defined &{__PACKAGE__ . "::$method"};
  4048         12938  
40 1633 100       2277 next if $method eq 'import';
41              
42 1541 50       2288 unless ($seen->{$method})
43             {
44 1541         2282 $seen->{$method} = $fullname;
45              
46 1541         4710 *{$method} = sub
47             {
48 182     182   15628 my $self = $_[0];
49              
50 182 100       396 if (ref $self eq __PACKAGE__)
51             {
52 180         191 shift @_;
53 180         312 my $super = "SUPER::$method";
54 180         2357 $self->$super(@_);
55             }
56             else
57             {
58 2         6 $method = "FileHandle::$method";
59 2         14 &$method(@_);
60             }
61 1541         4960 };
62             }
63             }
64              
65             # Traverse parent classes of this one
66 161         441 my @ISA = @{"$class\::ISA"};
  161         639  
67 161         861 for my $class (@ISA)
68             {
69 138         451 wrap_methods($class, $seen);
70             }
71             }
72              
73             wrap_methods('FileHandle');
74              
75             #-------------------------------------------------------------------------------
76              
77             sub DESTROY
78 0     0   0 {
79             }
80              
81             #-------------------------------------------------------------------------------
82              
83             sub new
84             {
85 48     48 1 30075 my $class = shift;
86              
87 48         65 my $self;
88              
89 48 100 100     388 if (defined $_[0] && defined fileno $_[0])
90             {
91 12         19 $self = shift;
92             }
93             else
94             {
95 36         247 $self = $class->SUPER::new(@_);
96 36 50       3779 return undef unless defined $self;
97             }
98              
99 48         185 my $values =
100             {
101             'fh' => $self,
102             'eof_called' => 0,
103             'filehandle_unget_buffer' => '',
104             };
105              
106 48         193 weaken($values->{'fh'});
107            
108 48         355 tie *$self, "${class}::Tie", $values;
109              
110 48         81 bless $self, $class;
111 48         108 return $self;
112             }
113              
114             #-------------------------------------------------------------------------------
115              
116             sub new_from_fd
117             {
118 1     1 1 54 my $class = shift;
119              
120 1         27 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       93 return undef unless defined $self;
130             }
131              
132 1         5 my $values =
133             {
134             'fh' => $self,
135             'eof_called' => 0,
136             'filehandle_unget_buffer' => '',
137             };
138              
139 1         10 weaken($values->{'fh'});
140            
141 1         7 tie *$self, "${class}::Tie", $values;
142              
143 1         3 bless $self, $class;
144 1         3 return $self;
145             }
146              
147             #-------------------------------------------------------------------------------
148              
149             sub ungetc
150             {
151 23     23 1 56 my $self = shift;
152 23         18 my $ord = shift;
153              
154 23         49 substr(tied(*$self)->{'filehandle_unget_buffer'},0,0) = chr($ord);
155             }
156              
157             #-------------------------------------------------------------------------------
158              
159             sub ungets
160             {
161 11     11 1 1397 my $self = shift;
162 11         20 my $string = shift;
163              
164 11         50 substr(tied(*$self)->{'filehandle_unget_buffer'},0,0) = $string;
165             }
166              
167             #-------------------------------------------------------------------------------
168              
169             sub buffer
170             {
171 3     3 1 7 my $self = shift;
172              
173 3 100       9 tied(*$self)->{'filehandle_unget_buffer'} = shift if @_;
174 3         14 return tied(*$self)->{'filehandle_unget_buffer'};
175             }
176              
177             #-------------------------------------------------------------------------------
178              
179             sub input_record_separator
180             {
181 3     3 1 324 my $self = shift;
182              
183 3 50       6 if(@_)
184             {
185 3         4 tied(*$self)->{'input_record_separator'} = shift;
186             }
187              
188 3 50       7 return undef unless exists tied(*$self)->{'input_record_separator'};
189 3         3 return tied(*$self)->{'input_record_separator'};
190             }
191              
192             #-------------------------------------------------------------------------------
193              
194             sub clear_input_record_separator
195             {
196 1     1 1 3 my $self = shift;
197              
198 1         3 delete tied(*$self)->{'input_record_separator'};
199             }
200              
201             ###############################################################################
202              
203             package FileHandle::Unget::Tie;
204              
205 23     23   136 use strict;
  23         12505  
  23         804  
206 23     23   303 use FileHandle;
  23         32  
  23         96  
207 23     23   23297 use bytes;
  23         210  
  23         95  
208              
209 23     23   905 use 5.000;
  23         58  
  23         804  
210              
211 23     23   93 use vars qw( $VERSION $AUTOLOAD @ISA );
  23         32  
  23         3746  
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   1043016 my $name = $AUTOLOAD;
231 59         490 $name =~ s/.*://;
232              
233 59 50       279 die "Unhandled function $name!" unless exists $tie_mapping{$name};
234              
235 59         135 my $sub = $tie_mapping{$name};
236              
237             # Alias the anonymous subroutine to the name of the sub we want ...
238 23     23   121 no strict 'refs';
  23         30  
  23         38682  
239 59         257 *{$name} = sub
240             {
241 143     143   10649 my $self = shift;
242              
243 143 100       518 if (defined &$sub)
244             {
245 92         298 &$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         58 local $^W = 0;
  51         234  
255 51         60 untie *{$self->{'fh'}};
  51         372  
256             }
257              
258 51         248 $self->{'fh'}->$sub(@_);
259              
260 51         827 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  51         259  
261             }
262 59         321 };
263              
264             # ... and go to it.
265 59         187 goto &$name;
266             }
267              
268             #-------------------------------------------------------------------------------
269              
270             sub DESTROY
271 0     0   0 {
272             }
273              
274             #-------------------------------------------------------------------------------
275              
276             sub TIEHANDLE
277             {
278 192     192   257 my $class = shift;
279 192         171 my $self = shift;
280              
281 192         281 bless($self, $class);
282              
283 192         565 return $self;
284             }
285              
286             #-------------------------------------------------------------------------------
287              
288             sub binmode
289             {
290 2     2   4 my $self = shift;
291              
292 2 100       137 warn "Under windows, calling binmode after eof exposes a bug that exists in some versions of Perl.\n"
293             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         10  
301 2         2 untie *{$self->{'fh'}};
  2         11  
302             }
303              
304 2 50       7 if (@_)
305             {
306 0         0 binmode $self->{'fh'}, @_;
307             }
308             else
309             {
310 2         6 binmode $self->{'fh'};
311             }
312              
313 2         4 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  2         7  
314             }
315              
316             #-------------------------------------------------------------------------------
317              
318             sub fileno
319             {
320 1     1   1 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         2  
328 1         2 untie *{$self->{'fh'}};
  1         5  
329             }
330              
331 1         3 my $fileno = fileno $self->{'fh'};
332              
333 1         1 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  1         2  
334              
335 1         8 return $fileno;
336             }
337              
338             #-------------------------------------------------------------------------------
339              
340             sub getline_wrapper
341             {
342 61 100   61   110 if (wantarray)
343             {
344 4         16 goto &getlines;
345             }
346             else
347             {
348 57         166 goto &getline;
349             }
350             }
351              
352             #-------------------------------------------------------------------------------
353              
354             sub getline
355             {
356 57     57   68 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         54 local $^W = 0;
  57         154  
364 57         58 untie *{$self->{'fh'}};
  57         271  
365             }
366              
367 57         60 my $line;
368              
369 57 100       153 local $/ = $self->{'input_record_separator'}
370             if exists $self->{'input_record_separator'};
371 57         99 my $input_record_separator = $/;
372              
373 57 100 100     578 if (defined $input_record_separator &&
    100          
374             $self->{'filehandle_unget_buffer'} =~ /(.*?$input_record_separator)/)
375             {
376 9         20 $line = $1;
377 9         31 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         10 $line = $self->{'filehandle_unget_buffer'};
388 5         16 $self->{'filehandle_unget_buffer'} = '';
389 5         35 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     297 @other_lines = () if @other_lines && !defined($other_lines[0]);
394              
395 5 50 66     33 if ($line eq '' && !@other_lines)
396             {
397 0         0 $line = undef;
398             }
399             else
400             {
401 5         17 $line .= join('', @other_lines);
402             }
403             }
404             else
405             {
406 43         66 $line = $self->{'filehandle_unget_buffer'};
407 43         63 $self->{'filehandle_unget_buffer'} = '';
408 43         155 my $templine = $self->{'fh'}->getline(@_);
409              
410 43 100 100     1530 if ($line eq '' && !defined $templine)
    50          
411             {
412 2         3 $line = undef;
413             }
414             elsif (defined $templine)
415             {
416 41         88 $line .= $templine;
417             }
418             }
419              
420 57         58 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  57         263  
421              
422 57         203 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         6 local $^W = 0;
  4         13  
437 4         6 untie *{$self->{'fh'}};
  4         17  
438             }
439              
440 4         8 my @buffer_lines;
441              
442 4 50       15 local $/ = $self->{'input_record_separator'}
443             if exists $self->{'input_record_separator'};
444 4         11 my $input_record_separator = $/;
445              
446 4 50       10 if (defined $input_record_separator)
447             {
448 4         122 $self->{'filehandle_unget_buffer'} =~
449 0         0 s/^(.*$input_record_separator)/push @buffer_lines, $1;''/mge;
  0         0  
450              
451 4         23 my @other_lines = $self->{'fh'}->getlines(@_);
452              
453 4 100       214 if (@other_lines)
454             {
455 3 50       14 if (defined $other_lines[0])
456             {
457 3         16 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         8 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  4         18  
494              
495 4         18 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   17 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         46 local $^W = 0;
  10         30  
542 10         9 untie *{$self->{'fh'}};
  10         55  
543             }
544              
545 10         16 my $scalar = \$_[0];
546 10         17 my $length = $_[1];
547 10         14 my $offset = $_[2];
548              
549 10         14 my $num_bytes_read = 0;
550              
551 10 100       30 if ($self->{'filehandle_unget_buffer'} ne '')
552             {
553 3         6 my $read_string = substr($self->{'filehandle_unget_buffer'},0,$length);
554 3         9 substr($self->{'filehandle_unget_buffer'},0,$length) = '';
555              
556 3         3 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       8 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       15 if (defined $_[2])
580             {
581 3         31 $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         13 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  10         35  
590              
591 10         29 return $num_bytes_read;
592             }
593              
594             #-------------------------------------------------------------------------------
595              
596             sub seek
597             {
598 3     3   3 my $self = shift;
599 3         2 my $position = $_[0];
600 3         2 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         5  
608 3         3 untie *{$self->{'fh'}};
  3         11  
609             }
610              
611 3 50 66     10 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         3 my $status;
618              
619             # First try to seek using the built-in seek
620 3 50       9 if (seek($self->{'fh'},$position,$whence))
621             {
622 3         3 $self->{'filehandle_unget_buffer'} = '';
623 3         2 $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         3 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  3         7  
656              
657 3         6 return $status;
658             }
659              
660             #-------------------------------------------------------------------------------
661              
662             sub tell
663             {
664 11     11   13 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         13 local $^W = 0;
  11         29  
672 11         14 untie *{$self->{'fh'}};
  11         56  
673             }
674              
675 11         23 my $file_position = tell $self->{'fh'};
676              
677 11 50       30 if ($file_position == -1)
678             {
679 0         0 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  0         0  
680 0         0 return -1;
681             }
682              
683 11         18 $file_position -= length($self->{'filehandle_unget_buffer'});
684              
685 11         13 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  11         41  
686              
687 11         42 return $file_position;
688             }
689              
690             #-------------------------------------------------------------------------------
691              
692             sub eof
693             {
694 4     4   8 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         5 local $^W = 0;
  4         16  
702 4         6 untie *{$self->{'fh'}};
  4         38  
703             }
704              
705 4         5 my $eof;
706              
707 4 50       17 if ($self->{'filehandle_unget_buffer'} ne '')
708             {
709 0         0 $eof = 0;
710             }
711             else
712             {
713 4         15 $eof = $self->{'fh'}->eof();
714             }
715              
716 4         3590 tie *{$self->{'fh'}}, __PACKAGE__, $self;
  4         31  
717              
718 4         11 $self->{'eof_called'} = 1;
719              
720 4         21 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__