Alt-CWB-ambs
view release on metacpan or search on metacpan
lib/CWB/CQP.pm view on Meta::CPAN
## CWB::CQP object constructor
sub new {
my $class = shift; # class name
my $self = {}; # namespace for new CQP class object
my @options = @_; # CQP command-line options (use at your own risk)
# split options with values, e.g. "-r /my/registry" => "-r", "/my/registry" (doesn't work for multiple options in one string)
@options = map { (/^(--?[A-Za-z0-9]+)\s+(.+)$/) ? ($1, $2) : $_ } @options;
## run CQP server in the background
my $in = $self->{'in'} = new FileHandle; # stdin of CQP
my $out = $self->{'out'} = new FileHandle; # stdout of CQP
my $err = $self->{'err'} = new FileHandle; # stderr of CQP
my $pid = open3($in, $out, $err, $CWB::CQP, @CQP_options, @options);
$self->{'pid'} = $pid; # child process ID (so process can be killed if necessary)
$in->autoflush(1); # make sure that commands sent to CQP are always flushed immediately
my ($need_major, $need_minor, $need_beta) = split /\./, $CQP_version; # required CQP version
$need_beta = 0 unless $need_beta;
my $version_string = $out->getline; # child mode (-c) should print version on startup
chomp $version_string;
croak "ERROR: CQP backend startup failed ('$CWB::CQP @CQP_options @options')\n"
unless $version_string =~ /^CQP\s+(?:\w+\s+)*([0-9]+)\.([0-9]+)(?:\.b?([0-9]+))?(?:\s+(.*))?$/;
$self->{'major_version'} = $1;
$self->{'minor_version'} = $2;
$self->{'beta_version'} = $3 || 0;
$self->{'compile_date'} = $4 || "unknown";
croak "ERROR: CQP version too old, need at least v$CQP_version ($version_string)\n"
unless ($1 > $need_major or
$1 == $need_major
and ($2 > $need_minor or
($2 == $need_minor and $3 >= $need_beta)));
## command execution
$self->{'command'} = undef; # CQP command string that is currently being processed (undef = last command has been completed)
$self->{'lines'} = []; # array of output lines read from CQP process
$self->{'buffer'} = ""; # read buffer for standard output from CQP process
$self->{'block_size'} = 256; # block size for reading from CQP's output and error streams
$self->{'query_lock'} = undef;# holds random key while query lock mode is active
## error handling (messages on stderr)
$self->{'error_handler'} = undef; # set to subref for user-defined error handler
$self->{'status'} = 'ok'; # status of last executed command ('ok' or 'error')
$self->{'error_message'} = []; # arrayref to array containing message produced by last command (if any)
## handling of CQP progress messages
$self->{'progress'} = 0; # whether progress messages are activated
$self->{'progress_handler'} = undef; # optional callback for progress messages
$self->{'progress_info'} = []; # contains last available progress information: [$total_percent, $pass, $n_passes, $message, $percent]
## debugging (prints more or less everything on stdout)
$self->{'debug'} = 0;
## select vectors for CQP output (stdout, stderr, stdout|stderr)
$self->{'select_err'} = new IO::Select($err);
$self->{'select_out'} = new IO::Select($out);
$self->{'select_any'} = new IO::Select($err, $out);
## CQP object setup complete
bless($self, $class);
## the following command will collect and ignore any output which may have been produced during startup
$self->exec("set PrettyPrint off"); # pretty-printing should be turned off for non-interactive use
return $self;
}
=item B<undef> I<$cqp>;
Exit CQP background process gracefully by issuing an C<exit;> command.
This is done automatically when the variable I<$cqp> goes out of scope.
Note that there may be a slight delay while B<CWB::CQP> waits for the CQP
process to terminate.
=cut
sub DESTROY {
my $self = shift;
if ($self->{'command'}) {
while ($self->_update) {} # read pending output from active command
}
my $out = $self->{'out'};
if (defined $out) {
$out->print("exit"); # exit CQP backend
$out->close;
}
my $in = $self->{'in'};
if (defined $in) {
$in->close;
}
my $pid = $self->{'pid'};
waitpid $pid, 0; # wait for CQP to exit and reap background process
## **TODO** -- this may hang in some cases; is there a safe workaround?
}
=item I<$ok> = I<$cqp>->B<check_version>(I<$major>, I<$minor>, I<$beta>);
Check for minimum required CQP version, i.e. the background process has
to be CQP version I<$major>.I<$minor>.I<$beta> or newer.
I<$minor> and I<$beta> may be omitted, in which case they default to 0.
Note that the B<CWB::CQP> module automatically checks whether the CQP version
is compatible with its own requirements when a new object is created.
The B<check_version> method can subsequently be used to check for a more
recent release that provides functionality needed by the Perl script.
=cut
sub check_version {
my $self = shift;
my ($major, $minor, $beta) = @_;
$minor = 0 unless defined $minor;
$beta = 0 unless defined $beta;
my $maj = $self->{'major_version'};
my $min = $self->{'minor_version'};
my $bet = $self->{'beta_version'};
if ($maj > $major or
($maj == $major
and ($min > $minor or
( run in 2.682 seconds using v1.01-cache-2.11-cpan-f56aa216473 )