| IO-Unread documentation | Contained in the IO-Unread distribution. |
IO::Unread - push more than one character back onto a filehandle
use IO::Unread;
unread STDIN, "hello world\n";
$_ = "goodbye";
unread ARGV;
IO::Unread exports one function, unread, which will push data back
onto a filehandle. Any amount of data can be pushed: if your perl is
built with PerlIO layers, the data is stored in a special :pending
layer; if not, the module ties the filehandle to a class which
returns the unread data and unties itself.
unread unreads LIST onto FILEHANDLE. If LIST is omitted, $_ is unread.
Returns the number of characters unread on success, undef on failure. Warnings
are produced under category io.
Note that unread $FH, 'a', 'b' is equivalent to
unread $FH, 'a'; unread $FH, 'b';
, ie. to unread $FH, 'ba' rather than unread $FH, 'ab'.
ungetc pushes the first character of STRING onto FILEHANDLE. Unlike
unread, it does not use a tie implementation if your perl doesn't
support PerlIO layers; rather it calls your ungetc(3). This is only
guarenteed to support one character of pushback, and then only if it is
the last character that was read from the handle.
None by default; unread, ungetc on request.
ungetc is subject to the whims of your libc if you're not using
perlio.
Copyright 2003 Ben Morrow <ben@morrow.me.uk>
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
PerlIO, perltie, ungetc(3)
| IO-Unread documentation | Contained in the IO-Unread distribution. |
package IO::Unread; use 5.008001; use warnings; use strict; use Carp; use XSLoader; use Symbol qw/qualify_to_ref/; use Scalar::Util qw/openhandle/; BEGIN { our $VERSION = '1.04'; XSLoader::load __PACKAGE__, $VERSION; } my $USE_PERLIO = HAVE_PERLIO_LAYERS; my $Debug; sub debug { my $func = (caller 1)[3]; $Debug and warn "$func: ", @_; } sub import { no strict 'refs'; my $from = shift; my $to = caller; my @carp; while ($_ = shift) { /^-tie$/ and do { $USE_PERLIO = 0; next; }; /^-debug$/ and do { $Debug = 1; debug "debugging on"; next; }; s/^&//; !/^_/ and /[^[:upper:]]/ and exists &{"$from\::$_"} and do { *{"$to\::$_"} = \&{"$from\::$_"}; next; }; push @carp, qq/"$_" is not exported by $from/; } @carp and do { carp $_ for @carp; croak "can't continue after import errors"; }; debug "import done"; } sub _get_fh { my $fh = do { local $^W = 0; qualify_to_ref shift, caller 2; }; openhandle $fh or return; debug "fh open"; _check_fh $fh or return; debug "fh mode good"; return $fh; } sub unread (*@) { { no warnings 'uninitialized'; debug '[', (join '][', @_), ']'; } my $fh = _get_fh shift or return; my $str = @_ ? (join "", reverse @_) : $_; length $str or return "0 but true"; my $rv; undef $@; if ($USE_PERLIO) { debug "using PerlIO_unread"; $rv = eval { _PerlIO_unread $fh, $str }; } else { debug "using IO::Unread::Tied"; tie *$fh, 'IO::Unread::Tied' => $fh, $str; $rv = length $str; } if ($@) { warnings::enabled "io" and carp $@; return; } defined $rv or return; $rv or return "0 but true"; return $rv; } sub ungetc (*;$) { my $fh = _get_fh shift or return; my $str = @_ ? shift : $_; length $str or return ''; my $rv = _PerlIO_ungetc $fh, substr $str, 0, 1; defined $rv or return; return $rv; } {{ package IO::Unread::Tied; use Tie::Handle 4.0; use base qw/Tie::Handle/; use Carp; BEGIN { *debug = \&IO::Unread::debug } sub TIEHANDLE { my ($c, $handle, $data) = @_; debug $data; $handle eq 'RETIE' and (debug "retieing"), return $data; length $data or croak __PACKAGE__."::TIEHANDLE called with null data"; return bless { handle => $handle, data => $data }, $c; } sub WRITE { my ($s, $data, $len, $off) = @_; debug; my $h = $s->{handle}; untie *$h; my $rv = print $h substr $data, 0, $off; tie *$h, ref $s => RETIE => $s; return $rv; } sub READ { my ($s, undef, $len, $off) = @_; my $h = $s->{handle}; my $rv = $len; debug; my $read = substr $s->{data}, 0, $len, ''; $len -= length $read; unless (length $s->{data}) { untie *$h; $rv = read $h, $read, $len, length $read; defined $rv and $rv += length $read; } substr($_[1], $off, 0) = $read; return $rv; } sub READLINE { my $s = shift; my $h = $s->{handle}; my $rv; debug; if (not defined $/) { untie *$h; return $s->{data} . <$h>; } if ($/ eq '') { $rv = $s->{data} =~ s!^ ([^\n]* \n+)!!x; $rv = $rv ? $1 : undef; } else { $rv = $s->{data} =~ s!^ (.*? \Q$/\E )!!x; $rv = $rv ? $1 : undef; } debug "rv = ", (defined $rv) ? (quotemeta $rv) : "(undef)"; unless (defined $rv) { $rv = $s->{data}; $s->{data} = ''; } if ($s->{data} eq '') { untie *$h; my $done = $rv =~ m! \Q$/\E $ !x; if ($/ eq '') { my $chr = getc $h; IO::Unread::ungetc $h, $chr; $done = ($chr ne "\n"); } debug "rv = |$rv|, \$/ = |$/|, done = $done"; $rv .= <$h> unless $done; } debug "rv = $rv"; return $rv; } sub CLOSE { untie *{$_[0]{handle}}; close $_[0]{handle}; } sub SEEK { my $s = shift; untie *{$s->{handle}}; seek $s->{handle}, $_[0], $_[1]; } sub TELL { untie *{$_[0]{handle}}; tell $_[0]{handle}; } sub UNTIE { debug; } }} 42;