AcePerl

 view release on metacpan or  search on metacpan

Ace/Local.pm  view on Meta::CPAN


sub connect {
  my $class = shift;
  my ($path,$program,$host,$port,$nosync) = rearrange(['PATH','PROGRAM','HOST','PORT','NOSYNC'],@_);
  my $args;
  
  # some pretty insane heuristics to handle BOTH tace and aceclient
  die "Specify either -path or -host and -port" if ($program && ($host || $port));
  die "-path is not relevant for aceclient, use -host and/or -port"
    if defined($program) && $program=~/aceclient/ && defined($path);
  die "-host and -port are not relevant for tace, use -path"
    if defined($program) && $program=~/tace/ and (defined $port || defined $host);
  
  # note, this relies on the programs being included in the current PATH
  my $prompt = 'acedb> ';
  if ($host || $port) {
    $program ||= 'aceclient';
    $prompt = "acedb\@$host> ";
  } else {
    $program ||= 'giface';
  }
  if ($program =~ /aceclient/) {
    $host ||= DEFAULT_HOST;
    $port ||= DEFAULT_PORT;
    $args = "$host -port $port";
  } else {
    $path ||= DEFAULT_DB;
    $path = _expand_twiddles($path);
    $args = $path;
  }
  
  my($rdr,$wtr) = (gensym,gensym);
  my($pid) = open2($rdr,$wtr,"$program $args");
  unless ($pid) {
    $Ace::Error = <$rdr>;
    return undef;
  }

  # Figure out the prompt by reading until we get zero length,
  # then take whatever's at the end.
  unless ($nosync) {
    local($/) = "> ";
    my $data = <$rdr>;
    ($prompt) = $data=~/^(.+> )/m;
    unless ($prompt) {
      $Ace::Error = "$program didn't open correctly";
      return undef;
    }
  }

  return bless {
		'read'   => $rdr,
		'write'  => $wtr,
		'prompt' => $prompt,
		'pid'    => $pid,
		'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);



( run in 3.048 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )