AcePerl
view release on metacpan or search on metacpan
Ace/Local.pm view on Meta::CPAN
'auto_save' => 1,
'status' => $nosync ? STATUS_PENDING : STATUS_WAITING, # initial stuff to read
},$class;
}
sub debug {
my $self = shift;
my $d = $self->{debug};
$self->{debug} = shift if @_;
$d;
}
sub DESTROY {
my $self = shift;
return unless kill 0,$self->{'pid'};
if ($self->auto_save) {
# save work for the user...
$self->query('save');
$self->synch;
}
$self->query('quit');
# just for paranoid reasons. shouldn't be necessary
close $self->{'write'} if $self->{'write'};
close $self->{'read'} if $self->{'read'};
waitpid($self->{pid},0) if $self->{'pid'};
}
sub encore {
my $self = shift;
return $self->status == STATUS_PENDING;
}
sub auto_save {
my $self = shift;
$self->{'auto_save'} = $_[0] if defined $_[0];
return $self->{'auto_save'};
}
sub status {
return $_[0]->{'status'};
}
sub error {
my $self = shift;
return $self->{'error'};
}
sub query {
my $self = shift;
my $query = shift;
warn "query($query)\n" if $self->debug;
if ($self->debug) {
my $msg = $query || '';
warn "\tquery($msg)";
}
return undef if $self->{'status'} == STATUS_ERROR;
do $self->read() until $self->{'status'} != STATUS_PENDING;
my $wtr = $self->{'write'};
print $wtr "$query\n";
$self->{'status'} = STATUS_PENDING;
}
sub low_read { # hack to accomodate "uninitialized database" warning from tace
my $self = shift;
my $rdr = $self->{'read'};
return undef unless $self->{'status'} == STATUS_PENDING;
my $rin = '';
my $data = '';
vec($rin,fileno($rdr),1)=1;
unless (select($rin,undef,undef,1)) {
$self->{'status'} = STATUS_WAITING;
return undef;
}
sysread($rdr,$data,READSIZE);
return $data;
}
sub read {
my $self = shift;
return undef unless $self->{'status'} == STATUS_PENDING;
my $rdr = $self->{'read'};
my $len = defined $self->{'buffer'} ? length($self->{'buffer'}) : 0;
my $plen = length($self->{'prompt'});
my ($result, $bytes, $pos, $searchfrom);
while (1) {
# Read the data directly onto the end of the buffer
$bytes = sysread($rdr, $self->{'buffer'},
READSIZE, $len);
unless ($bytes > 0) {
$self->{'status'} = STATUS_ERROR;
return;
}
# check for prompt
# The following checks were implemented using regexps and $' and
# friends. I have changed this to use {r}index and substr (a)
# because they're much faster than regexps and (b) because using
# $' and $` causes all regexps in a program to execute
# very slowly due to excessive and unnecessary pre/post-match
# copying -- tim.cutts@incyte.com 08 Sep 1999
# Note, don't need to search the whole buffer for the prompt;
# just need to search the new data and the prompt length from
# any previous data.
$searchfrom = ($len <= $plen) ? 0 : ($len - $plen);
if (($pos = index($self->{'buffer'},
$self->{'prompt'},
$searchfrom)) > 0) {
$self->{'status'} = STATUS_WAITING;
$result = substr($self->{'buffer'}, 0, $pos);
$self->{'buffer'} = '';
return $result;
}
# return partial results for paragraph breaks
if (($pos = rindex($self->{'buffer'}, "\n\n")) > 0) {
$result = substr($self->{'buffer'}, 0, $pos + 2);
$self->{'buffer'} = substr($self->{'buffer'},
$pos + 2);
return $result;
}
$len += $bytes;
}
# never get here
}
# just throw away everything
sub synch {
my $self = shift;
$self->read() while $self->status == STATUS_PENDING;
}
# expand ~foo syntax
sub _expand_twiddles {
my $path = shift;
my ($to_expand,$homedir);
return $path unless $path =~ m!^~([^/]*)!;
if ($to_expand = $1) {
$homedir = (getpwnam($to_expand))[7];
} else {
$homedir = (getpwuid($<))[7];
}
return $path unless $homedir;
$path =~ s!^~[^/]*!$homedir!;
return $path;
}
__END__
=head1 NAME
Ace::Local - use giface, tace or gifaceclient to open a local connection to an Ace database
=head1 SYNOPSIS
use Ace::Local
my $ace = Ace::Local->connect(-path=>'/usr/local/acedb/elegans');
$ace->query('find author Se*');
die "Query unsuccessful" unless $ace->status;
$ace->query('show');
while ($ace->encore) {
print $ace->read;
}
=head1 DESCRIPTION
This class is provided for low-level access to local (non-networked)
Ace databases via the I<giface> program. You will generally not need
to access it directly. Use Ace.pm instead.
For the sake of completeness, the method can also use the I<aceclient>
program for its access. However the Ace::AceDB class is more efficient
for this purpose.
=head1 METHODS
=head2 connect()
$accessor = Ace::Local->connect(-path=>$path_to_database);
Connect to the database at the indicated path using I<giface> and
return a connection object (an "accessor"). I<Giface> must be on the
current search path. Multiple accessors may be open simultaneously.
Arguments include:
=over 4
=item B<-path>
Path to the database (location of the "wspec/" directory).
=item B<-program>
Used to indicate the location of the desired I<giface> or
I<gifaceclient> executable. You may also use I<tace> or I<aceclient>,
but in that case the asGIF() functionality will nog work. Can be used
to override the search path.
=item B<-host>
Used when invoking I<gifaceclient>. Indicates the host to connect to.
=item B<-port>
Used when invoking I<gifaceclient>. Indicates the port to connect to.
=item B<-nosync>
Ordinarily Ace::Local synchronizes with the tace/giface prompt,
throwing out all warnings and copyright messages. If this is set,
Ace::Local will not do so. In this case you must call the low_read()
method until it returns undef in order to synchronize.
=back
=head2 query()
$status = $accessor->query('query string');
Send the query string to the server and return a true value if
successful. You must then call read() repeatedly in order to fetch
( run in 0.611 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )