426 lines
7.6 KiB
Perl
426 lines
7.6 KiB
Perl
package IO::String;
|
|
|
|
# Copyright 1998-2005 Gisle Aas.
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the same terms as Perl itself.
|
|
|
|
require 5.005_03;
|
|
use strict;
|
|
use vars qw($VERSION $DEBUG $IO_CONSTANTS);
|
|
$VERSION = "1.08"; # $Date: 2005/12/05 12:00:47 $
|
|
|
|
use Symbol ();
|
|
|
|
sub new
|
|
{
|
|
my $class = shift;
|
|
my $self = bless Symbol::gensym(), ref($class) || $class;
|
|
tie *$self, $self;
|
|
$self->open(@_);
|
|
return $self;
|
|
}
|
|
|
|
sub open
|
|
{
|
|
my $self = shift;
|
|
return $self->new(@_) unless ref($self);
|
|
|
|
if (@_) {
|
|
my $bufref = ref($_[0]) ? $_[0] : \$_[0];
|
|
$$bufref = "" unless defined $$bufref;
|
|
*$self->{buf} = $bufref;
|
|
}
|
|
else {
|
|
my $buf = "";
|
|
*$self->{buf} = \$buf;
|
|
}
|
|
*$self->{pos} = 0;
|
|
*$self->{lno} = 0;
|
|
return $self;
|
|
}
|
|
|
|
sub pad
|
|
{
|
|
my $self = shift;
|
|
my $old = *$self->{pad};
|
|
*$self->{pad} = substr($_[0], 0, 1) if @_;
|
|
return "\0" unless defined($old) && length($old);
|
|
return $old;
|
|
}
|
|
|
|
sub dump
|
|
{
|
|
require Data::Dumper;
|
|
my $self = shift;
|
|
print Data::Dumper->Dump([$self], ['*self']);
|
|
print Data::Dumper->Dump([*$self{HASH}], ['$self{HASH}']);
|
|
return;
|
|
}
|
|
|
|
sub TIEHANDLE
|
|
{
|
|
print "TIEHANDLE @_\n" if $DEBUG;
|
|
return $_[0] if ref($_[0]);
|
|
my $class = shift;
|
|
my $self = bless Symbol::gensym(), $class;
|
|
$self->open(@_);
|
|
return $self;
|
|
}
|
|
|
|
sub DESTROY
|
|
{
|
|
print "DESTROY @_\n" if $DEBUG;
|
|
}
|
|
|
|
sub close
|
|
{
|
|
my $self = shift;
|
|
delete *$self->{buf};
|
|
delete *$self->{pos};
|
|
delete *$self->{lno};
|
|
undef *$self if $] eq "5.008"; # workaround for some bug
|
|
return 1;
|
|
}
|
|
|
|
sub opened
|
|
{
|
|
my $self = shift;
|
|
return defined *$self->{buf};
|
|
}
|
|
|
|
sub binmode
|
|
{
|
|
my $self = shift;
|
|
return 1 unless @_;
|
|
# XXX don't know much about layers yet :-(
|
|
return 0;
|
|
}
|
|
|
|
sub getc
|
|
{
|
|
my $self = shift;
|
|
my $buf;
|
|
return $buf if $self->read($buf, 1);
|
|
return undef;
|
|
}
|
|
|
|
sub ungetc
|
|
{
|
|
my $self = shift;
|
|
$self->setpos($self->getpos() - 1);
|
|
return 1;
|
|
}
|
|
|
|
sub eof
|
|
{
|
|
my $self = shift;
|
|
return length(${*$self->{buf}}) <= *$self->{pos};
|
|
}
|
|
|
|
sub print
|
|
{
|
|
my $self = shift;
|
|
if (defined $\) {
|
|
if (defined $,) {
|
|
$self->write(join($,, @_).$\);
|
|
}
|
|
else {
|
|
$self->write(join("",@_).$\);
|
|
}
|
|
}
|
|
else {
|
|
if (defined $,) {
|
|
$self->write(join($,, @_));
|
|
}
|
|
else {
|
|
$self->write(join("",@_));
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
*printflush = \*print;
|
|
|
|
sub printf
|
|
{
|
|
my $self = shift;
|
|
print "PRINTF(@_)\n" if $DEBUG;
|
|
my $fmt = shift;
|
|
$self->write(sprintf($fmt, @_));
|
|
return 1;
|
|
}
|
|
|
|
|
|
my($SEEK_SET, $SEEK_CUR, $SEEK_END);
|
|
|
|
sub _init_seek_constants
|
|
{
|
|
if ($IO_CONSTANTS) {
|
|
require IO::Handle;
|
|
$SEEK_SET = &IO::Handle::SEEK_SET;
|
|
$SEEK_CUR = &IO::Handle::SEEK_CUR;
|
|
$SEEK_END = &IO::Handle::SEEK_END;
|
|
}
|
|
else {
|
|
$SEEK_SET = 0;
|
|
$SEEK_CUR = 1;
|
|
$SEEK_END = 2;
|
|
}
|
|
}
|
|
|
|
|
|
sub seek
|
|
{
|
|
my($self,$off,$whence) = @_;
|
|
my $buf = *$self->{buf} || return 0;
|
|
my $len = length($$buf);
|
|
my $pos = *$self->{pos};
|
|
|
|
_init_seek_constants() unless defined $SEEK_SET;
|
|
|
|
if ($whence == $SEEK_SET) { $pos = $off }
|
|
elsif ($whence == $SEEK_CUR) { $pos += $off }
|
|
elsif ($whence == $SEEK_END) { $pos = $len + $off }
|
|
else { die "Bad whence ($whence)" }
|
|
print "SEEK(POS=$pos,OFF=$off,LEN=$len)\n" if $DEBUG;
|
|
|
|
$pos = 0 if $pos < 0;
|
|
$self->truncate($pos) if $pos > $len; # extend file
|
|
*$self->{pos} = $pos;
|
|
return 1;
|
|
}
|
|
|
|
sub pos
|
|
{
|
|
my $self = shift;
|
|
my $old = *$self->{pos};
|
|
if (@_) {
|
|
my $pos = shift || 0;
|
|
my $buf = *$self->{buf};
|
|
my $len = $buf ? length($$buf) : 0;
|
|
$pos = $len if $pos > $len;
|
|
*$self->{pos} = $pos;
|
|
}
|
|
return $old;
|
|
}
|
|
|
|
sub getpos { shift->pos; }
|
|
|
|
*sysseek = \&seek;
|
|
*setpos = \&pos;
|
|
*tell = \&getpos;
|
|
|
|
|
|
|
|
sub getline
|
|
{
|
|
my $self = shift;
|
|
my $buf = *$self->{buf} || return;
|
|
my $len = length($$buf);
|
|
my $pos = *$self->{pos};
|
|
return if $pos >= $len;
|
|
|
|
unless (defined $/) { # slurp
|
|
*$self->{pos} = $len;
|
|
return substr($$buf, $pos);
|
|
}
|
|
|
|
unless (length $/) { # paragraph mode
|
|
# XXX slow&lazy implementation using getc()
|
|
my $para = "";
|
|
my $eol = 0;
|
|
my $c;
|
|
while (defined($c = $self->getc)) {
|
|
if ($c eq "\n") {
|
|
$eol++;
|
|
next if $eol > 2;
|
|
}
|
|
elsif ($eol > 1) {
|
|
$self->ungetc($c);
|
|
last;
|
|
}
|
|
else {
|
|
$eol = 0;
|
|
}
|
|
$para .= $c;
|
|
}
|
|
return $para; # XXX wantarray
|
|
}
|
|
|
|
my $idx = index($$buf,$/,$pos);
|
|
if ($idx < 0) {
|
|
# return rest of it
|
|
*$self->{pos} = $len;
|
|
$. = ++ *$self->{lno};
|
|
return substr($$buf, $pos);
|
|
}
|
|
$len = $idx - $pos + length($/);
|
|
*$self->{pos} += $len;
|
|
$. = ++ *$self->{lno};
|
|
return substr($$buf, $pos, $len);
|
|
}
|
|
|
|
sub getlines
|
|
{
|
|
die "getlines() called in scalar context\n" unless wantarray;
|
|
my $self = shift;
|
|
my($line, @lines);
|
|
push(@lines, $line) while defined($line = $self->getline);
|
|
return @lines;
|
|
}
|
|
|
|
sub READLINE
|
|
{
|
|
goto &getlines if wantarray;
|
|
goto &getline;
|
|
}
|
|
|
|
sub input_line_number
|
|
{
|
|
my $self = shift;
|
|
my $old = *$self->{lno};
|
|
*$self->{lno} = shift if @_;
|
|
return $old;
|
|
}
|
|
|
|
sub truncate
|
|
{
|
|
my $self = shift;
|
|
my $len = shift || 0;
|
|
my $buf = *$self->{buf};
|
|
if (length($$buf) >= $len) {
|
|
substr($$buf, $len) = '';
|
|
*$self->{pos} = $len if $len < *$self->{pos};
|
|
}
|
|
else {
|
|
$$buf .= ($self->pad x ($len - length($$buf)));
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
sub read
|
|
{
|
|
my $self = shift;
|
|
my $buf = *$self->{buf};
|
|
return undef unless $buf;
|
|
|
|
my $pos = *$self->{pos};
|
|
my $rem = length($$buf) - $pos;
|
|
my $len = $_[1];
|
|
$len = $rem if $len > $rem;
|
|
return undef if $len < 0;
|
|
if (@_ > 2) { # read offset
|
|
substr($_[0],$_[2]) = substr($$buf, $pos, $len);
|
|
}
|
|
else {
|
|
$_[0] = substr($$buf, $pos, $len);
|
|
}
|
|
*$self->{pos} += $len;
|
|
return $len;
|
|
}
|
|
|
|
sub write
|
|
{
|
|
my $self = shift;
|
|
my $buf = *$self->{buf};
|
|
return unless $buf;
|
|
|
|
my $pos = *$self->{pos};
|
|
my $slen = length($_[0]);
|
|
my $len = $slen;
|
|
my $off = 0;
|
|
if (@_ > 1) {
|
|
$len = $_[1] if $_[1] < $len;
|
|
if (@_ > 2) {
|
|
$off = $_[2] || 0;
|
|
die "Offset outside string" if $off > $slen;
|
|
if ($off < 0) {
|
|
$off += $slen;
|
|
die "Offset outside string" if $off < 0;
|
|
}
|
|
my $rem = $slen - $off;
|
|
$len = $rem if $rem < $len;
|
|
}
|
|
}
|
|
substr($$buf, $pos, $len) = substr($_[0], $off, $len);
|
|
*$self->{pos} += $len;
|
|
return $len;
|
|
}
|
|
|
|
*sysread = \&read;
|
|
*syswrite = \&write;
|
|
|
|
sub stat
|
|
{
|
|
my $self = shift;
|
|
return unless $self->opened;
|
|
return 1 unless wantarray;
|
|
my $len = length ${*$self->{buf}};
|
|
|
|
return (
|
|
undef, undef, # dev, ino
|
|
0666, # filemode
|
|
1, # links
|
|
$>, # user id
|
|
$), # group id
|
|
undef, # device id
|
|
$len, # size
|
|
undef, # atime
|
|
undef, # mtime
|
|
undef, # ctime
|
|
512, # blksize
|
|
int(($len+511)/512) # blocks
|
|
);
|
|
}
|
|
|
|
sub FILENO {
|
|
return undef; # XXX perlfunc says this means the file is closed
|
|
}
|
|
|
|
sub blocking {
|
|
my $self = shift;
|
|
my $old = *$self->{blocking} || 0;
|
|
*$self->{blocking} = shift if @_;
|
|
return $old;
|
|
}
|
|
|
|
my $notmuch = sub { return };
|
|
|
|
*fileno = $notmuch;
|
|
*error = $notmuch;
|
|
*clearerr = $notmuch;
|
|
*sync = $notmuch;
|
|
*flush = $notmuch;
|
|
*setbuf = $notmuch;
|
|
*setvbuf = $notmuch;
|
|
|
|
*untaint = $notmuch;
|
|
*autoflush = $notmuch;
|
|
*fcntl = $notmuch;
|
|
*ioctl = $notmuch;
|
|
|
|
*GETC = \&getc;
|
|
*PRINT = \&print;
|
|
*PRINTF = \&printf;
|
|
*READ = \&read;
|
|
*WRITE = \&write;
|
|
*SEEK = \&seek;
|
|
*TELL = \&getpos;
|
|
*EOF = \&eof;
|
|
*CLOSE = \&close;
|
|
*BINMODE = \&binmode;
|
|
|
|
|
|
sub string_ref
|
|
{
|
|
my $self = shift;
|
|
return *$self->{buf};
|
|
}
|
|
*sref = \&string_ref;
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
#line 552
|