home *** CD-ROM | disk | FTP | other *** search
- package IO::Select::Trap;
-
- use strict;
- use IO::Select;
-
- use vars qw/$VERSION/;
- $VERSION = '0.03';
-
- sub new {
- my $pkg = shift;
- my $opts = (ref $_[0] eq 'HASH') ? shift : {};
- my $self = bless {
- ioselect => new IO::Select(),
- handles => {},
- traps => ($opts->{traps} or 'String|Scalar'),
- debug => (exists $opts->{debug} ? $opts->{debug} : 1),
- }, (ref $pkg || $pkg);
-
- $self->add(@_) if @_;
- $self;
- }
-
- sub _update {
- my ($self) = shift;
- my $add = shift eq 'add';
-
- my @pthru;
- foreach my $h (@_) {
- next unless defined $h;
- unless ($self->_trapped($h)) {
- push @pthru, $h;
- next;
- }
-
- if ($add) {
- $self->{handles}->{\*{$h}} = $h;
- } else {
- delete $_[0]->{handles}->{\*{$h}};
- }
- }
- return \@pthru;
- }
-
- sub _trapped {
- my ($self, $h) = @_;
- (ref $h) =~ /$self->{traps}/i;
- }
-
- sub _count {
- my $self = shift;
- return scalar keys %{$self->{handles}};
- }
-
- sub _can_read {
- my $self = shift;
- return unless $self->_count;
- my @result;
- while (my ($k, $h) = each %{$self->{handles}}) {
- push @result, $h if (length ${$h->sref});
- }
- return wantarray ? @result : \@result;
- }
-
- sub _can_write {
- my $self = shift;
- return unless $self->_count;
- my @result;
- while (my ($k, $h) = each %{$self->{handles}}) {
- push @result, $h if ($h->opened);
- }
- return wantarray ? @result : \@result;
- }
-
- sub _has_exception {}
-
- sub add {
- my $self = shift;
- my $pthru = $self->_update('add', @_);
- $self->{ioselect}->add(@$pthru) if @$pthru;
- }
-
- sub remove {
- my $self = shift;
- my $pthru = $self->_update('remove', @_);
- $self->{ioselect}->remove(@$pthru) if @$pthru;
- }
-
- sub select {
- shift if defined $_[0] && !ref($_[0]);
- my ($r, $w, $e, $t) = @_;
- my (@RR, @WR, @ER);
-
- my $rready = defined $r ? $r->_can_read : undef;
- my $wready = defined $w ? $w->_can_write : undef;
- my $eready = defined $e ? $e->_has_exception : undef;
-
- push @RR, @$rready if defined $rready;
- push @WR, @$wready if defined $wready;
- push @ER, @$eready if defined $eready;
-
- my ($ir) = defined $r ? $r->{ioselect} : undef;
- my ($iw) = defined $w ? $w->{ioselect} : undef;
- my ($ie) = defined $e ? $e->{ioselect} : undef;
-
- if (@RR || @WR || @ER) {
- $t = 0 unless (defined $t); # Force non-blocking select()
- }
-
- ($rready, $wready, $eready) = IO::Select->select($ir, $iw, $ie, $t);
- push @RR, @$rready if defined $rready;
- push @WR, @$wready if defined $wready;
- push @ER, @$eready if defined $eready;
-
-
- return (\@RR, \@WR, \@ER);
- }
-
- sub exists {
- return unless defined $_[1];
- exists $_[0]->{handles}->{\*{$_[1]}};
- }
-
- sub can_read {
- my ($self, $t) = @_;
- my @hready = $self->_can_read();
- $t = 0 if (! defined $t && @hready);
- my @iready = $self->{ioselect}->can_read($t);
- return
- @iready ?
- @hready ? (@iready, @hready) : @iready
- : @hready;
- }
-
- sub can_write {
- my ($self, $t) = @_;
- my @hready = $self->_can_write();
- $t = 0 if (! defined $t && @hready);
- my @iready = $self->{ioselect}->can_write($t);
- return
- @iready ?
- @hready ? (@iready, @hready) : @iready
- : @hready;
- }
-
- sub has_exception {
- my ($self, $t) = @_;
- my @hready = $self->_has_exception();
- $t = 0 if (! defined $t && @hready);
- my @iready = $self->{ioselect}->has_exception($t);
- return
- @iready ?
- @hready ? (@iready, @hready) : @iready
- : @hready;
- }
-
- sub count {
- my $self = shift;
- return $self->{ioselect}->count
- + scalar keys %{$self->{handles}};
- }
-
- sub _debug {
- my $self = shift;
- print STDERR "$self: ", @_ if $self->{debug};
- }
-
-
- 1;
- __END__
-
- =head1 NAME
-
- IO::Select::Trap - IO::Select() functionality on Scalar-based Filehandles
-
- =head1 SYNOPSIS
-
- use IO::Select::Trap;
- use IO::String;
-
- my $ios = new IO::String();
- my $sock = new IO::Socket();
- my $rb = new IO::Select::Trap(<{ trap=>'Scalar|String' }>, $ios, $sock);
- my $wb = new IO::Select::Trap(<{ trap=>'Scalar|String' }>, $ios, $sock);
- my ($rready, $wready) = IO::Select::Trap->select($rb, $wb);
-
- =head1 DESCRIPTION
-
- IO::Select::Trap is a wrapper for C<IO::Select> which enables use of the
- C<IO::Select-E<gt>select()> method on IO::Scalar or IO::String
- object/filehandles. Other filehandle object types (ie IO::Socket) are passed
- through to IO::Select for processing. Most of the IO::Select interface is
- supported.
-
- An IO::String/Scalar object/filehandle is ready for reading when it contains
- some amount of data. It will always be ready for writing. Also, IO::String/Scalar
- objects will *never* block.
-
- When calling select(), the trapped objects are evaluated first. If any
- are found to be ready, the IO::Select->select() is called with a timeout of
- '0'. Otherwise it is called with the supplied timeout (or undef).
-
- =head1 OPTIONS
-
- =over 4
-
- =item trap I<experimental>
-
- REGEX that specifies the IO objects to trap.
-
- =back
-
- =head1 LIMITATIONS
-
- Currently, the select(), can_read(), etc. methods only support
- trapped IO::Scalar or IO::String objects. Other trapped objects will
- probably break the tests that the methods use to determine read/write ability.
-
- The is a bug when using IO::Scalar objects, in that two IO::Scalars can't be
- compared. Eg:
-
- $ios = new IO::Scalar;
- $ios2 = $ios;
-
- if ($ios == $ios2) { #...
-
- .. causes a runtime error. A fix has been sent to to the author, and should be
- included in a future version.
-
- =head1 AUTHOR & COPYRIGHT
-
- Scott Scecina, E<lt>scotts@inmind.comE<gt>
-
- Except where otherwise noted, IO::Select::Trap is
- Copyright 2001 Scott Scecina. All rights reserved.
- IO::Select::Trap is free software; you may redistribute
- it and/or modify it under the same terms as Perl itself.
-
- =head1 SEE ALSO
-
- L<IO::Select>.
-
- =cut
-