Debian lenny version packages
[pkg-perl] / deb-src / libio-stringy-perl / io-stringy-2.110 / lib / IO / Scalar.pm
diff --git a/deb-src/libio-stringy-perl/io-stringy-2.110/lib/IO/Scalar.pm b/deb-src/libio-stringy-perl/io-stringy-2.110/lib/IO/Scalar.pm
new file mode 100644 (file)
index 0000000..7a52282
--- /dev/null
@@ -0,0 +1,778 @@
+package IO::Scalar;
+
+
+=head1 NAME
+
+IO::Scalar - IO:: interface for reading/writing a scalar
+
+
+=head1 SYNOPSIS
+
+Perform I/O on strings, using the basic OO interface...
+
+    use 5.005;
+    use IO::Scalar;
+    $data = "My message:\n";
+
+    ### Open a handle on a string, and append to it:
+    $SH = new IO::Scalar \$data;
+    $SH->print("Hello");
+    $SH->print(", world!\nBye now!\n");
+    print "The string is now: ", $data, "\n";
+
+    ### Open a handle on a string, read it line-by-line, then close it:
+    $SH = new IO::Scalar \$data;
+    while (defined($_ = $SH->getline)) {
+       print "Got line: $_";
+    }
+    $SH->close;
+
+    ### Open a handle on a string, and slurp in all the lines:
+    $SH = new IO::Scalar \$data;
+    print "All lines:\n", $SH->getlines;
+
+    ### Get the current position (either of two ways):
+    $pos = $SH->getpos;
+    $offset = $SH->tell;
+
+    ### Set the current position (either of two ways):
+    $SH->setpos($pos);
+    $SH->seek($offset, 0);
+
+    ### Open an anonymous temporary scalar:
+    $SH = new IO::Scalar;
+    $SH->print("Hi there!");
+    print "I printed: ", ${$SH->sref}, "\n";      ### get at value
+
+
+Don't like OO for your I/O?  No problem.
+Thanks to the magic of an invisible tie(), the following now
+works out of the box, just as it does with IO::Handle:
+
+    use 5.005;
+    use IO::Scalar;
+    $data = "My message:\n";
+
+    ### Open a handle on a string, and append to it:
+    $SH = new IO::Scalar \$data;
+    print $SH "Hello";
+    print $SH ", world!\nBye now!\n";
+    print "The string is now: ", $data, "\n";
+
+    ### Open a handle on a string, read it line-by-line, then close it:
+    $SH = new IO::Scalar \$data;
+    while (<$SH>) {
+       print "Got line: $_";
+    }
+    close $SH;
+
+    ### Open a handle on a string, and slurp in all the lines:
+    $SH = new IO::Scalar \$data;
+    print "All lines:\n", <$SH>;
+
+    ### Get the current position (WARNING: requires 5.6):
+    $offset = tell $SH;
+
+    ### Set the current position (WARNING: requires 5.6):
+    seek $SH, $offset, 0;
+
+    ### Open an anonymous temporary scalar:
+    $SH = new IO::Scalar;
+    print $SH "Hi there!";
+    print "I printed: ", ${$SH->sref}, "\n";      ### get at value
+
+
+And for you folks with 1.x code out there: the old tie() style still works,
+though this is I<unnecessary and deprecated>:
+
+    use IO::Scalar;
+
+    ### Writing to a scalar...
+    my $s;
+    tie *OUT, 'IO::Scalar', \$s;
+    print OUT "line 1\nline 2\n", "line 3\n";
+    print "String is now: $s\n"
+
+    ### Reading and writing an anonymous scalar...
+    tie *OUT, 'IO::Scalar';
+    print OUT "line 1\nline 2\n", "line 3\n";
+    tied(OUT)->seek(0,0);
+    while (<OUT>) {
+        print "Got line: ", $_;
+    }
+
+
+Stringification works, too!
+
+    my $SH = new IO::Scalar \$data;
+    print $SH "Hello, ";
+    print $SH "world!";
+    print "I printed: $SH\n";
+
+
+
+=head1 DESCRIPTION
+
+This class is part of the IO::Stringy distribution;
+see L<IO::Stringy> for change log and general information.
+
+The IO::Scalar class implements objects which behave just like
+IO::Handle (or FileHandle) objects, except that you may use them
+to write to (or read from) scalars.  These handles are
+automatically tiehandle'd (though please see L<"WARNINGS">
+for information relevant to your Perl version).
+
+
+Basically, this:
+
+    my $s;
+    $SH = new IO::Scalar \$s;
+    $SH->print("Hel", "lo, ");         ### OO style
+    $SH->print("world!\n");            ### ditto
+
+Or this:
+
+    my $s;
+    $SH = tie *OUT, 'IO::Scalar', \$s;
+    print OUT "Hel", "lo, ";           ### non-OO style
+    print OUT "world!\n";              ### ditto
+
+Causes $s to be set to:
+
+    "Hello, world!\n"
+
+
+=head1 PUBLIC INTERFACE
+
+=cut
+
+use Carp;
+use strict;
+use vars qw($VERSION @ISA);
+use IO::Handle;
+
+use 5.005;
+
+### Stringification, courtesy of B. K. Oxley (binkley):  :-)
+use overload '""'   => sub { ${*{$_[0]}->{SR}} };
+use overload 'bool' => sub { 1 };      ### have to do this, so object is true!
+
+### The package version, both in 1.23 style *and* usable by MakeMaker:
+$VERSION = "2.110";
+
+### Inheritance:
+@ISA = qw(IO::Handle);
+
+### This stuff should be got rid of ASAP.
+require IO::WrapTie and push @ISA, 'IO::WrapTie::Slave' if ($] >= 5.004);
+
+#==============================
+
+=head2 Construction
+
+=over 4
+
+=cut
+
+#------------------------------
+
+=item new [ARGS...]
+
+I<Class method.>
+Return a new, unattached scalar handle.
+If any arguments are given, they're sent to open().
+
+=cut
+
+sub new {
+    my $proto = shift;
+    my $class = ref($proto) || $proto;
+    my $self = bless \do { local *FH }, $class;
+    tie *$self, $class, $self;
+    $self->open(@_);   ### open on anonymous by default
+    $self;
+}
+sub DESTROY {
+    shift->close;
+}
+
+#------------------------------
+
+=item open [SCALARREF]
+
+I<Instance method.>
+Open the scalar handle on a new scalar, pointed to by SCALARREF.
+If no SCALARREF is given, a "private" scalar is created to hold
+the file data.
+
+Returns the self object on success, undefined on error.
+
+=cut
+
+sub open {
+    my ($self, $sref) = @_;
+
+    ### Sanity:
+    defined($sref) or do {my $s = ''; $sref = \$s};
+    (ref($sref) eq "SCALAR") or croak "open() needs a ref to a scalar";
+
+    ### Setup:
+    *$self->{Pos} = 0;          ### seek position
+    *$self->{SR}  = $sref;      ### scalar reference
+    $self;
+}
+
+#------------------------------
+
+=item opened
+
+I<Instance method.>
+Is the scalar handle opened on something?
+
+=cut
+
+sub opened {
+    *{shift()}->{SR};
+}
+
+#------------------------------
+
+=item close
+
+I<Instance method.>
+Disassociate the scalar handle from its underlying scalar.
+Done automatically on destroy.
+
+=cut
+
+sub close {
+    my $self = shift;
+    %{*$self} = ();
+    1;
+}
+
+=back
+
+=cut
+
+
+
+#==============================
+
+=head2 Input and output
+
+=over 4
+
+=cut
+
+
+#------------------------------
+
+=item flush
+
+I<Instance method.>
+No-op, provided for OO compatibility.
+
+=cut
+
+sub flush { "0 but true" }
+
+#------------------------------
+
+=item getc
+
+I<Instance method.>
+Return the next character, or undef if none remain.
+
+=cut
+
+sub getc {
+    my $self = shift;
+
+    ### Return undef right away if at EOF; else, move pos forward:
+    return undef if $self->eof;
+    substr(${*$self->{SR}}, *$self->{Pos}++, 1);
+}
+
+#------------------------------
+
+=item getline
+
+I<Instance method.>
+Return the next line, or undef on end of string.
+Can safely be called in an array context.
+Currently, lines are delimited by "\n".
+
+=cut
+
+sub getline {
+    my $self = shift;
+
+    ### Return undef right away if at EOF:
+    return undef if $self->eof;
+
+    ### Get next line:
+    my $sr = *$self->{SR};
+    my $i  = *$self->{Pos};            ### Start matching at this point.
+
+    ### Minimal impact implementation!
+    ### We do the fast fast thing (no regexps) if using the
+    ### classic input record separator.
+
+    ### Case 1: $/ is undef: slurp all...
+    if    (!defined($/)) {
+       *$self->{Pos} = length $$sr;
+        return substr($$sr, $i);
+    }
+
+    ### Case 2: $/ is "\n": zoom zoom zoom...
+    elsif ($/ eq "\012") {
+
+        ### Seek ahead for "\n"... yes, this really is faster than regexps.
+        my $len = length($$sr);
+        for (; $i < $len; ++$i) {
+           last if ord (substr ($$sr, $i, 1)) == 10;
+        }
+
+        ### Extract the line:
+        my $line;
+        if ($i < $len) {                ### We found a "\n":
+            $line = substr ($$sr, *$self->{Pos}, $i - *$self->{Pos} + 1);
+            *$self->{Pos} = $i+1;            ### Remember where we finished up.
+        }
+        else {                          ### No "\n"; slurp the remainder:
+            $line = substr ($$sr, *$self->{Pos}, $i - *$self->{Pos});
+            *$self->{Pos} = $len;
+        }
+        return $line;
+    }
+
+    ### Case 3: $/ is ref to int. Do fixed-size records.
+    ###        (Thanks to Dominique Quatravaux.)
+    elsif (ref($/)) {
+        my $len = length($$sr);
+               my $i = ${$/} + 0;
+               my $line = substr ($$sr, *$self->{Pos}, $i);
+               *$self->{Pos} += $i;
+        *$self->{Pos} = $len if (*$self->{Pos} > $len);
+               return $line;
+    }
+
+    ### Case 4: $/ is either "" (paragraphs) or something weird...
+    ###         This is Graham's general-purpose stuff, which might be
+    ###         a tad slower than Case 2 for typical data, because
+    ###         of the regexps.
+    else {
+        pos($$sr) = $i;
+
+       ### If in paragraph mode, skip leading lines (and update i!):
+        length($/) or
+           (($$sr =~ m/\G\n*/g) and ($i = pos($$sr)));
+
+        ### If we see the separator in the buffer ahead...
+        if (length($/)
+           ?  $$sr =~ m,\Q$/\E,g          ###   (ordinary sep) TBD: precomp!
+            :  $$sr =~ m,\n\n,g            ###   (a paragraph)
+            ) {
+            *$self->{Pos} = pos $$sr;
+            return substr($$sr, $i, *$self->{Pos}-$i);
+        }
+        ### Else if no separator remains, just slurp the rest:
+        else {
+            *$self->{Pos} = length $$sr;
+            return substr($$sr, $i);
+        }
+    }
+}
+
+#------------------------------
+
+=item getlines
+
+I<Instance method.>
+Get all remaining lines.
+It will croak() if accidentally called in a scalar context.
+
+=cut
+
+sub getlines {
+    my $self = shift;
+    wantarray or croak("can't call getlines in scalar context!");
+    my ($line, @lines);
+    push @lines, $line while (defined($line = $self->getline));
+    @lines;
+}
+
+#------------------------------
+
+=item print ARGS...
+
+I<Instance method.>
+Print ARGS to the underlying scalar.
+
+B<Warning:> this continues to always cause a seek to the end
+of the string, but if you perform seek()s and tell()s, it is
+still safer to explicitly seek-to-end before subsequent print()s.
+
+=cut
+
+sub print {
+    my $self = shift;
+    *$self->{Pos} = length(${*$self->{SR}} .= join('', @_) . (defined($\) ? $\ : ""));
+    1;
+}
+sub _unsafe_print {
+    my $self = shift;
+    my $append = join('', @_) . $\;
+    ${*$self->{SR}} .= $append;
+    *$self->{Pos}   += length($append);
+    1;
+}
+sub _old_print {
+    my $self = shift;
+    ${*$self->{SR}} .= join('', @_) . $\;
+    *$self->{Pos} = length(${*$self->{SR}});
+    1;
+}
+
+
+#------------------------------
+
+=item read BUF, NBYTES, [OFFSET]
+
+I<Instance method.>
+Read some bytes from the scalar.
+Returns the number of bytes actually read, 0 on end-of-file, undef on error.
+
+=cut
+
+sub read {
+    my $self = $_[0];
+    my $n    = $_[2];
+    my $off  = $_[3] || 0;
+
+    my $read = substr(${*$self->{SR}}, *$self->{Pos}, $n);
+    $n = length($read);
+    *$self->{Pos} += $n;
+    ($off ? substr($_[1], $off) : $_[1]) = $read;
+    return $n;
+}
+
+#------------------------------
+
+=item write BUF, NBYTES, [OFFSET]
+
+I<Instance method.>
+Write some bytes to the scalar.
+
+=cut
+
+sub write {
+    my $self = $_[0];
+    my $n    = $_[2];
+    my $off  = $_[3] || 0;
+
+    my $data = substr($_[1], $off, $n);
+    $n = length($data);
+    $self->print($data);
+    return $n;
+}
+
+#------------------------------
+
+=item sysread BUF, LEN, [OFFSET]
+
+I<Instance method.>
+Read some bytes from the scalar.
+Returns the number of bytes actually read, 0 on end-of-file, undef on error.
+
+=cut
+
+sub sysread {
+  my $self = shift;
+  $self->read(@_);
+}
+
+#------------------------------
+
+=item syswrite BUF, NBYTES, [OFFSET]
+
+I<Instance method.>
+Write some bytes to the scalar.
+
+=cut
+
+sub syswrite {
+  my $self = shift;
+  $self->write(@_);
+}
+
+=back
+
+=cut
+
+
+#==============================
+
+=head2 Seeking/telling and other attributes
+
+=over 4
+
+=cut
+
+
+#------------------------------
+
+=item autoflush
+
+I<Instance method.>
+No-op, provided for OO compatibility.
+
+=cut
+
+sub autoflush {}
+
+#------------------------------
+
+=item binmode
+
+I<Instance method.>
+No-op, provided for OO compatibility.
+
+=cut
+
+sub binmode {}
+
+#------------------------------
+
+=item clearerr
+
+I<Instance method.>  Clear the error and EOF flags.  A no-op.
+
+=cut
+
+sub clearerr { 1 }
+
+#------------------------------
+
+=item eof
+
+I<Instance method.>  Are we at end of file?
+
+=cut
+
+sub eof {
+    my $self = shift;
+    (*$self->{Pos} >= length(${*$self->{SR}}));
+}
+
+#------------------------------
+
+=item seek OFFSET, WHENCE
+
+I<Instance method.>  Seek to a given position in the stream.
+
+=cut
+
+sub seek {
+    my ($self, $pos, $whence) = @_;
+    my $eofpos = length(${*$self->{SR}});
+
+    ### Seek:
+    if    ($whence == 0) { *$self->{Pos} = $pos }             ### SEEK_SET
+    elsif ($whence == 1) { *$self->{Pos} += $pos }            ### SEEK_CUR
+    elsif ($whence == 2) { *$self->{Pos} = $eofpos + $pos}    ### SEEK_END
+    else                 { croak "bad seek whence ($whence)" }
+
+    ### Fixup:
+    if (*$self->{Pos} < 0)       { *$self->{Pos} = 0 }
+    if (*$self->{Pos} > $eofpos) { *$self->{Pos} = $eofpos }
+    return 1;
+}
+
+#------------------------------
+
+=item sysseek OFFSET, WHENCE
+
+I<Instance method.> Identical to C<seek OFFSET, WHENCE>, I<q.v.>
+
+=cut
+
+sub sysseek {
+    my $self = shift;
+    $self->seek (@_);
+}
+
+#------------------------------
+
+=item tell
+
+I<Instance method.>
+Return the current position in the stream, as a numeric offset.
+
+=cut
+
+sub tell { *{shift()}->{Pos} }
+
+#------------------------------
+#
+# use_RS [YESNO]
+#
+# I<Instance method.>
+# Obey the curent setting of $/, like IO::Handle does?
+# Default is false in 1.x, but cold-welded true in 2.x and later.
+#
+sub use_RS {
+    my ($self, $yesno) = @_;
+    carp "use_RS is deprecated and ignored; \$/ is always consulted\n";
+ }
+
+#------------------------------
+
+=item setpos POS
+
+I<Instance method.>
+Set the current position, using the opaque value returned by C<getpos()>.
+
+=cut
+
+sub setpos { shift->seek($_[0],0) }
+
+#------------------------------
+
+=item getpos
+
+I<Instance method.>
+Return the current position in the string, as an opaque object.
+
+=cut
+
+*getpos = \&tell;
+
+
+#------------------------------
+
+=item sref
+
+I<Instance method.>
+Return a reference to the underlying scalar.
+
+=cut
+
+sub sref { *{shift()}->{SR} }
+
+
+#------------------------------
+# Tied handle methods...
+#------------------------------
+
+# Conventional tiehandle interface:
+sub TIEHANDLE {
+    ((defined($_[1]) && UNIVERSAL::isa($_[1], "IO::Scalar"))
+     ? $_[1]
+     : shift->new(@_));
+}
+sub GETC      { shift->getc(@_) }
+sub PRINT     { shift->print(@_) }
+sub PRINTF    { shift->print(sprintf(shift, @_)) }
+sub READ      { shift->read(@_) }
+sub READLINE  { wantarray ? shift->getlines(@_) : shift->getline(@_) }
+sub WRITE     { shift->write(@_); }
+sub CLOSE     { shift->close(@_); }
+sub SEEK      { shift->seek(@_); }
+sub TELL      { shift->tell(@_); }
+sub EOF       { shift->eof(@_); }
+
+#------------------------------------------------------------
+
+1;
+
+__END__
+
+
+
+=back
+
+=cut
+
+
+=head1 WARNINGS
+
+Perl's TIEHANDLE spec was incomplete prior to 5.005_57;
+it was missing support for C<seek()>, C<tell()>, and C<eof()>.
+Attempting to use these functions with an IO::Scalar will not work
+prior to 5.005_57. IO::Scalar will not have the relevant methods
+invoked; and even worse, this kind of bug can lie dormant for a while.
+If you turn warnings on (via C<$^W> or C<perl -w>),
+and you see something like this...
+
+    attempt to seek on unopened filehandle
+
+...then you are probably trying to use one of these functions
+on an IO::Scalar with an old Perl.  The remedy is to simply
+use the OO version; e.g.:
+
+    $SH->seek(0,0);    ### GOOD: will work on any 5.005
+    seek($SH,0,0);     ### WARNING: will only work on 5.005_57 and beyond
+
+
+=head1 VERSION
+
+$Id: Scalar.pm,v 1.6 2005/02/10 21:21:53 dfs Exp $
+
+
+=head1 AUTHORS
+
+=head2 Primary Maintainer
+
+David F. Skoll (F<dfs@roaringpenguin.com>).
+
+=head2 Principal author
+
+Eryq (F<eryq@zeegee.com>).
+President, ZeeGee Software Inc (F<http://www.zeegee.com>).
+
+
+=head2 Other contributors
+
+The full set of contributors always includes the folks mentioned
+in L<IO::Stringy/"CHANGE LOG">.  But just the same, special
+thanks to the following individuals for their invaluable contributions
+(if I've forgotten or misspelled your name, please email me!):
+
+I<Andy Glew,>
+for contributing C<getc()>.
+
+I<Brandon Browning,>
+for suggesting C<opened()>.
+
+I<David Richter,>
+for finding and fixing the bug in C<PRINTF()>.
+
+I<Eric L. Brine,>
+for his offset-using read() and write() implementations.
+
+I<Richard Jones,>
+for his patches to massively improve the performance of C<getline()>
+and add C<sysread> and C<syswrite>.
+
+I<B. K. Oxley (binkley),>
+for stringification and inheritance improvements,
+and sundry good ideas.
+
+I<Doug Wilson,>
+for the IO::Handle inheritance and automatic tie-ing.
+
+
+=head1 SEE ALSO
+
+L<IO::String>, which is quite similar but which was designed
+more-recently and with an IO::Handle-like interface in mind,
+so you could mix OO- and native-filehandle usage without using tied().
+
+I<Note:> as of version 2.x, these classes all work like
+their IO::Handle counterparts, so we have comparable
+functionality to IO::String.
+
+=cut
+