File Coverage

blib/lib/CWB/CQI/Client.pm
Criterion Covered Total %
statement 21 483 4.3
branch 0 104 0.0
condition 0 54 0.0
subroutine 7 78 8.9
pod 0 71 0.0
total 28 790 3.5


line stmt bran cond sub pod time code
1             package CWB::CQI::Client;
2             # -*-cperl-*-
3             $VERSION = 'v3.5.0';
4              
5 2     2   1208 use strict;
  2         3  
  2         48  
6 2     2   8 use warnings;
  2         3  
  2         40  
7              
8 2     2   7 use CWB::CQI;
  2         3  
  2         27  
9 2     2   1570 use Socket;
  2         6737  
  2         705  
10 2     2   784 use FileHandle;
  2         21540  
  2         11  
11 2     2   618 use Carp;
  2         5  
  2         130  
12              
13             # export CQi client functions
14 2     2   12 use base qw(Exporter);
  2         2  
  2         15511  
15             our @EXPORT = (
16             qw,
17             qw,
18             qw,
19             qw,
20             );
21              
22             =head1 NAME
23              
24             CWB::CQI::Client - CQi client library (reference implementation)
25              
26              
27             =head1 SYNOPSIS
28              
29             use CWB::CQI::Client;
30              
31             ** TODO **
32              
33              
34             =head1 DESCRIPTION
35              
36             B<** TODO **>
37              
38             =head1 CQi COMMANDS
39              
40             B<** TODO **> (add inline POD documentation to each function definition)
41              
42             =cut
43              
44              
45             our $conn = new FileHandle;
46              
47              
48             #
49             #
50             # Error Handling
51             #
52             #
53              
54             our $LastCmd = ""; # keep track of last command in case we receive an error code
55              
56             sub CqiError (@) {
57 0     0 0   foreach (@_) {
58 0           print STDERR "CQi ERROR: $_\n";
59             }
60 0           croak "CQI::Client -- connection aborted.";
61 0           exit 1; # Perl/Tk seems to catch the croak ...
62             }
63              
64             sub CqiErrorCode ($) {
65 0     0 0   my $errcode = shift;
66 0           my $group = $errcode >> 8;
67 0           my $command = $errcode & 0xff;
68 0           my $errhex = sprintf "%02X:%02X", $group, $command;
69 0           my $name = $CWB::CQI::CommandName{$errcode};
70            
71 0 0         if ($name =~ /ERROR/) {
72 0           CqiError "Received $name [$errhex] in response to", "$LastCmd";
73             }
74             else {
75 0           CqiError "Unexpected response $name [$errhex] to", "$LastCmd";
76             }
77             }
78              
79             sub CqiCheckResponse ($@) {
80 0     0 0   my $response = shift;
81 0           my %expect = map { $_ => 1 } @_;
  0            
82            
83             CqiErrorCode $response
84 0 0         unless defined $expect{$response};
85             }
86              
87              
88             #
89             #
90             # Connect to CQi server / Disconnect
91             #
92             #
93              
94             sub cqi_connect {
95 0     0 0   my $user = shift;
96 0           my $passwd = shift;
97 0           my $host = shift; # optional
98 0           my $port = shift; # optional
99              
100 0 0         $host = 'localhost'
101             unless defined $host;
102 0 0         $port = $CWB::CQI::PORT
103             unless defined $port;
104              
105 0 0 0       croak "USAGE: cqi_connect(username, password, [, remotehost [, port]]);"
106             unless defined $user and defined $passwd;
107 0           $LastCmd = "CQI_CTRL_CONNECT($user, '$passwd', $host, $port)";
108              
109 0           my $ipaddr = inet_aton($host);
110 0           my $sockaddr = sockaddr_in($port, $ipaddr);
111 0           my $protocol = getprotobyname('tcp');
112              
113             socket($conn, PF_INET, SOCK_STREAM, $protocol)
114 0 0         or do { croak "cqi_connect(): $!", exit 1};
  0            
115             connect($conn, $sockaddr)
116 0 0         or do { croak "cqi_connect(): $!", exit 1};
  0            
117              
118 0           cqi_send_word($CWB::CQI::CTRL_CONNECT);
119 0           cqi_send_string($user);
120 0           cqi_send_string($passwd);
121 0           cqi_flush();
122              
123 0           my $response = cqi_read_word();
124 0           CqiCheckResponse $response, $CWB::CQI::STATUS_CONNECT_OK;
125             }
126              
127             sub cqi_bye {
128 0     0 0   $LastCmd = "CQI_CTRL_BYE()";
129 0           cqi_send_word($CWB::CQI::CTRL_BYE);
130 0           cqi_flush();
131 0           my $response = cqi_read_word();
132 0           CqiCheckResponse $response, $CWB::CQI::STATUS_BYE_OK;
133 0           $conn->close;
134 0           $conn = undef;
135             }
136              
137             sub cqi_ping {
138 0     0 0   $LastCmd = "CQI_CTRL_PING()";
139 0           cqi_send_word($CWB::CQI::CTRL_PING);
140 0           cqi_flush();
141 0           CqiCheckResponse cqi_read_word(), $CWB::CQI::STATUS_PING_OK;
142             }
143              
144              
145             #
146             #
147             # CQi Commands
148             #
149             #
150              
151             sub cqi_ask_feature {
152 0     0 0   my $feature = lc shift;
153 0           my %features = (
154             "cqi1.0" => $CWB::CQI::ASK_FEATURE_CQI_1_0,
155             "cl2.3" => $CWB::CQI::ASK_FEATURE_CL_2_3,
156             "cqp2.3" => $CWB::CQI::ASK_FEATURE_CQP_2_3,
157             );
158             croak "USAGE: \$supported = cqi_ask_feature('cqi1.0' | 'cl2.3' | 'cqp2.3');"
159 0 0         unless defined $features{$feature};
160 0           $LastCmd = $CWB::CQI::CommandName{$features{$feature}} . "()";
161 0           cqi_send_word($features{$feature});
162 0           cqi_flush();
163 0           return cqi_expect_bool();
164             }
165              
166             sub cqi_list_corpora {
167 0     0 0   $LastCmd = "CQI_CORPUS_LIST_CORPORA()";
168 0 0         croak "USAGE: \@corpora = cqi_list_corpora();"
169             unless @_ == 0;
170 0           cqi_send_word($CWB::CQI::CORPUS_LIST_CORPORA);
171 0           cqi_flush();
172 0           return cqi_expect_string_list();
173             }
174              
175             sub cqi_charset {
176 0     0 0   my $corpus = shift;
177 0           $LastCmd = "CQI_CORPUS_CHARSET($corpus)";
178 0           cqi_send_word($CWB::CQI::CORPUS_CHARSET);
179 0           cqi_send_string($corpus);
180 0           cqi_flush();
181 0           return cqi_expect_string();
182             }
183              
184             sub cqi_properties {
185 0     0 0   my $corpus = shift;
186 0           $LastCmd = "CQI_CORPUS_PROPERTIES($corpus)";
187 0           cqi_send_word($CWB::CQI::CORPUS_PROPERTIES);
188 0           cqi_send_string($corpus);
189 0           cqi_flush();
190 0           return cqi_expect_string_list();
191             }
192              
193             sub cqi_attributes {
194 0     0 0   my $corpus = shift;
195 0           my $type = shift;
196 0           my %types = (
197             'p' => $CWB::CQI::CORPUS_POSITIONAL_ATTRIBUTES,
198             's' => $CWB::CQI::CORPUS_STRUCTURAL_ATTRIBUTES,
199             'a' => $CWB::CQI::CORPUS_ALIGNMENT_ATTRIBUTES,
200             );
201             croak "USAGE: \@attributes = cqi_attributes(\$corpus, ('p'|'s'|'a'));"
202 0 0         unless defined $types{$type};
203 0           $LastCmd = $CWB::CQI::CommandName{$types{$type}} . "($corpus)";
204 0           cqi_send_word($types{$type});
205 0           cqi_send_string($corpus);
206 0           cqi_flush();
207 0           return cqi_expect_string_list();
208             }
209              
210             sub cqi_structural_attribute_has_values {
211 0     0 0   my $attribute = shift;
212 0           $LastCmd = "CQI_CORPUS_STRUCTURAL_ATTRIBUTE_HAS_VALUES($attribute)";
213 0           cqi_send_word($CWB::CQI::CORPUS_STRUCTURAL_ATTRIBUTE_HAS_VALUES);
214 0           cqi_send_string($attribute);
215 0           cqi_flush();
216 0           return cqi_expect_bool();
217             }
218              
219             sub cqi_full_name {
220 0     0 0   my $corpus = shift;
221 0           $LastCmd = "CQI_CORPUS_FULL_NAME($corpus)";
222 0           cqi_send_word($CWB::CQI::CORPUS_FULL_NAME);
223 0           cqi_send_string($corpus);
224 0           cqi_flush();
225 0           return cqi_expect_string();
226             }
227              
228             sub cqi_corpus_info {
229 0     0 0   my $corpus = shift;
230 0           $LastCmd = "CQI_CORPUS_INFO($corpus)";
231 0           cqi_send_word($CWB::CQI::CORPUS_INFO);
232 0           cqi_send_string($corpus);
233 0           cqi_flush();
234 0           return cqi_expect_string_list();
235             }
236              
237             sub cqi_drop_corpus {
238 0     0 0   my $corpus = shift;
239 0           $LastCmd = "CQI_CORPUS_DROP_CORPUS($corpus)";
240 0           cqi_send_word($CWB::CQI::CORPUS_DROP_CORPUS);
241 0           cqi_send_string($corpus);
242 0           cqi_flush();
243 0           cqi_expect_status($CWB::CQI::STATUS_OK);
244             }
245              
246             sub cqi_attribute_size {
247 0     0 0   my $attribute = shift;
248 0           $LastCmd = "CQI_CL_ATTRIBUTE_SIZE($attribute)";
249 0           cqi_send_word($CWB::CQI::CL_ATTRIBUTE_SIZE);
250 0           cqi_send_string($attribute);
251 0           cqi_flush();
252 0           return cqi_expect_int();
253             }
254              
255             sub cqi_lexicon_size {
256 0     0 0   my $attribute = shift;
257 0           $LastCmd = "CQI_CL_LEXICON_SIZE($attribute)";
258 0           cqi_send_word($CWB::CQI::CL_LEXICON_SIZE);
259 0           cqi_send_string($attribute);
260 0           cqi_flush();
261 0           return cqi_expect_int();
262             }
263              
264             sub cqi_drop_attribute {
265 0     0 0   my $attribute = shift;
266 0           $LastCmd = "CQI_CL_DROP_ATTRIBUTE($attribute)";
267 0           cqi_send_word($CWB::CQI::CL_DROP_ATTRIBUTE);
268 0           cqi_send_string($attribute);
269 0           cqi_flush();
270 0           cqi_expect_status($CWB::CQI::STATUS_OK);
271             }
272              
273             # 'scalar' functions which map to lists in the CQi are wrapped
274             # in a scalar-safe client interface, so we CAN use them with simple
275             # scalars in CQI::Client.
276             sub cqi_str2id {
277 0     0 0   my $attribute = shift;
278 0           $LastCmd = "CQI_CL_STR2ID($attribute, [@_])";
279 0           cqi_send_word($CWB::CQI::CL_STR2ID);
280 0           cqi_send_string($attribute);
281 0           cqi_send_string_list(@_);
282 0           cqi_flush();
283 0           my @list = cqi_expect_int_list();
284 0 0         if (wantarray) {
285 0           return @list;
286             }
287             else {
288 0 0         croak "Called in scalar context with list argument." unless @list == 1;
289 0           return $list[0];
290             }
291             }
292              
293             sub cqi_id2str {
294 0     0 0   my $attribute = shift;
295 0           $LastCmd = "CQI_CL_ID2STR($attribute, [@_])";
296 0           cqi_send_word($CWB::CQI::CL_ID2STR);
297 0           cqi_send_string($attribute);
298 0           cqi_send_int_list(@_);
299 0           cqi_flush();
300 0           my @list = cqi_expect_string_list();
301 0 0         if (wantarray) {
302 0           return @list;
303             }
304             else {
305 0 0         croak "Called in scalar context with list argument." unless @list == 1;
306 0           return $list[0];
307             }
308             }
309              
310             sub cqi_id2freq {
311 0     0 0   my $attribute = shift;
312 0           $LastCmd = "CQI_CL_ID2FREQ($attribute, [@_])";
313 0           cqi_send_word($CWB::CQI::CL_ID2FREQ);
314 0           cqi_send_string($attribute);
315 0           cqi_send_int_list(@_);
316 0           cqi_flush();
317 0           my @list = cqi_expect_int_list();
318 0 0         if (wantarray) {
319 0           return @list;
320             }
321             else {
322 0 0         croak "Called in scalar context with list argument." unless @list == 1;
323 0           return $list[0];
324             }
325             }
326              
327             sub cqi_cpos2id {
328 0     0 0   my $attribute = shift;
329 0           $LastCmd = "CQI_CL_CPOS2ID($attribute, [@_])";
330 0           cqi_send_word($CWB::CQI::CL_CPOS2ID);
331 0           cqi_send_string($attribute);
332 0           cqi_send_int_list(@_);
333 0           cqi_flush();
334 0           my @list = cqi_expect_int_list();
335 0 0         if (wantarray) {
336 0           return @list;
337             }
338             else {
339 0 0         croak "Called in scalar context with list argument." unless @list == 1;
340 0           return $list[0];
341             }
342             }
343              
344             sub cqi_cpos2str {
345 0     0 0   my $attribute = shift;
346 0           $LastCmd = "CQI_CL_CPOS2STR($attribute, [@_])";
347 0           cqi_send_word($CWB::CQI::CL_CPOS2STR);
348 0           cqi_send_string($attribute);
349 0           cqi_send_int_list(@_);
350 0           cqi_flush();
351 0           my @list = cqi_expect_string_list();
352 0 0         if (wantarray) {
353 0           return @list;
354             }
355             else {
356 0 0         croak "Called in scalar context with list argument." unless @list == 1;
357 0           return $list[0];
358             }
359             }
360              
361             sub cqi_cpos2struc {
362 0     0 0   my $attribute = shift;
363 0           $LastCmd = "CQI_CL_CPOS2STRUC($attribute, [@_])";
364 0           cqi_send_word($CWB::CQI::CL_CPOS2STRUC);
365 0           cqi_send_string($attribute);
366 0           cqi_send_int_list(@_);
367 0           cqi_flush();
368 0           my @list = cqi_expect_int_list();
369 0 0         if (wantarray) {
370 0           return @list;
371             }
372             else {
373 0 0         croak "Called in scalar context with list argument." unless @list == 1;
374 0           return $list[0];
375             }
376             }
377              
378             sub cqi_cpos2lbound {
379 0     0 0   my $attribute = shift;
380 0           $LastCmd = "CQI_CL_CPOS2LBOUND($attribute, [@_])";
381 0           cqi_send_word($CWB::CQI::CL_CPOS2LBOUND);
382 0           cqi_send_string($attribute);
383 0           cqi_send_int_list(@_);
384 0           cqi_flush();
385 0           my @list = cqi_expect_int_list();
386 0 0         if (wantarray) {
387 0           return @list;
388             }
389             else {
390 0 0         croak "Called in scalar context with list argument." unless @list == 1;
391 0           return $list[0];
392             }
393             }
394              
395             sub cqi_cpos2rbound {
396 0     0 0   my $attribute = shift;
397 0           $LastCmd = "CQI_CL_CPOS2RBOUND($attribute, [@_])";
398 0           cqi_send_word($CWB::CQI::CL_CPOS2RBOUND);
399 0           cqi_send_string($attribute);
400 0           cqi_send_int_list(@_);
401 0           cqi_flush();
402 0           my @list = cqi_expect_int_list();
403 0 0         if (wantarray) {
404 0           return @list;
405             }
406             else {
407 0 0         croak "Called in scalar context with list argument." unless @list == 1;
408 0           return $list[0];
409             }
410             }
411              
412             sub cqi_cpos2alg {
413 0     0 0   my $attribute = shift;
414 0           $LastCmd = "CQI_CL_CPOS2ALG($attribute, [@_])";
415 0           cqi_send_word($CWB::CQI::CL_CPOS2ALG);
416 0           cqi_send_string($attribute);
417 0           cqi_send_int_list(@_);
418 0           cqi_flush();
419 0           my @list = cqi_expect_int_list();
420 0 0         if (wantarray) {
421 0           return @list;
422             }
423             else {
424 0 0         croak "Called in scalar context with list argument." unless @list == 1;
425 0           return $list[0];
426             }
427             }
428              
429             sub cqi_struc2str {
430 0     0 0   my $attribute = shift;
431 0           $LastCmd = "CQI_CL_STRUC2STR($attribute, [@_])";
432 0           cqi_send_word($CWB::CQI::CL_STRUC2STR);
433 0           cqi_send_string($attribute);
434 0           cqi_send_int_list(@_);
435 0           cqi_flush();
436 0           my @list = cqi_expect_string_list();
437 0 0         if (wantarray) {
438 0           return @list;
439             }
440             else {
441 0 0         croak "Called in scalar context with list argument." unless @list == 1;
442 0           return $list[0];
443             }
444             }
445              
446             sub cqi_id2cpos {
447 0 0 0 0 0   croak "USAGE: \@cposlist = cqi_id2cpos(\$attribute, \$id);"
448             unless @_ == 2 and wantarray;
449 0           my $attribute = shift;
450 0           my $id = shift;
451              
452 0           $LastCmd = "CQI_CL_ID2CPOS($attribute, $id)";
453 0           cqi_send_word($CWB::CQI::CL_ID2CPOS);
454 0           cqi_send_string($attribute);
455 0           cqi_send_int($id);
456 0           cqi_flush();
457 0           return cqi_expect_int_list();
458             }
459              
460             sub cqi_idlist2cpos {
461 0     0 0   my $attribute = shift;
462 0           $LastCmd = "CQI_CL_IDLIST2CPOS($attribute, [@_])";
463 0           cqi_send_word($CWB::CQI::CL_IDLIST2CPOS);
464 0           cqi_send_string($attribute);
465 0           cqi_send_int_list(@_);
466 0           cqi_flush();
467 0           return cqi_expect_int_list();
468             }
469              
470             sub cqi_regex2id {
471 0 0 0 0 0   croak "USAGE: \@idlist = cqi_regex2id(\$attribute, \$regex);"
472             unless @_ == 2 and wantarray;
473 0           my $attribute = shift;
474 0           my $regex = shift;
475              
476 0           $LastCmd = "CQI_CL_REGEX2ID($attribute, $regex)";
477 0           cqi_send_word($CWB::CQI::CL_REGEX2ID);
478 0           cqi_send_string($attribute);
479 0           cqi_send_string($regex);
480 0           cqi_flush();
481 0           return cqi_expect_int_list();
482             }
483              
484             sub cqi_struc2cpos {
485 0 0 0 0 0   croak "USAGE: (\$start, \$end) = cqi_struc2cpos(\$attribute, \$struc);"
486             unless @_ == 2 and wantarray;
487 0           my $attribute = shift;
488 0           my $struc = shift;
489              
490 0           $LastCmd = "CQI_CL_STRUC2CPOS($attribute, $struc)";
491 0           cqi_send_word($CWB::CQI::CL_STRUC2CPOS);
492 0           cqi_send_string($attribute);
493 0           cqi_send_int($struc);
494 0           cqi_flush();
495 0           return cqi_expect_int_int();
496             }
497              
498             sub cqi_alg2cpos {
499 0 0 0 0 0   croak "USAGE: (\$s1, \$s2, \$t1, \$t2) = cqi_alg2cpos(\$attribute, \$alg);"
500             unless @_ == 2 and wantarray;
501 0           my $attribute = shift;
502 0           my $alg = shift;
503              
504 0           $LastCmd = "CQI_CL_ALG2CPOS($attribute, $alg)";
505 0           cqi_send_word($CWB::CQI::CL_ALG2CPOS);
506 0           cqi_send_string($attribute);
507 0           cqi_send_int($alg);
508 0           cqi_flush();
509 0           return cqi_expect_int_int_int_int();
510             }
511              
512             # cqi_query() returns a CQi response code (CQI_STATUS_OK or error).
513             # An error code usually indicates a mistake in the query syntax.
514             # It aborts the program unless one of the following responses is received:
515             # CQI_STATUS_OK
516             # CQI_ERROR_*
517             # CQI_CQP_ERROR_*
518             sub cqi_query {
519 0     0 0   my ($mother, $child, $query) = @_;
520 0 0 0       croak "USAGE: \$ok = cqi_query(\$mother_corpus, \$subcorpus_name, \$query);"
      0        
521             unless @_ == 3 and $mother =~ /^[A-Z0-9_-]+(:[A-Z_][A-Za-z0-9_-]*)?$/
522             and $child =~ /^[A-Z_][A-Za-z0-9_-]*$/;
523 0 0         $query .= ";"
524             unless $query =~ /;\s*$/;
525            
526 0           $LastCmd = "CQI_CQP_QUERY($mother, $child, '$query')";
527 0           cqi_send_word($CWB::CQI::CQP_QUERY);
528 0           cqi_send_string($mother);
529 0           cqi_send_string($child);
530 0           cqi_send_string($query);
531 0           cqi_flush();
532 0           my $response = cqi_read_word();
533 0           my $group = $response >> 8;
534 0 0 0       CqiError $response
      0        
535             unless $response == $CWB::CQI::STATUS_OK or $group == $CWB::CQI::ERROR or $group == $CWB::CQI::CQP_ERROR;
536 0           return $response;
537             }
538              
539             sub cqi_list_subcorpora {
540 0     0 0   my $corpus = shift;
541 0           $LastCmd = "CQI_CQP_LIST_SUBCORPORA($corpus)";
542 0           cqi_send_word($CWB::CQI::CQP_LIST_SUBCORPORA);
543 0           cqi_send_string($corpus);
544 0           cqi_flush();
545 0           return cqi_expect_string_list();
546             }
547              
548             sub cqi_subcorpus_size {
549 0     0 0   my $subcorpus = shift;
550 0           $LastCmd = "CQI_CQP_SUBCORPUS_SIZE($subcorpus)";
551 0           cqi_send_word($CWB::CQI::CQP_SUBCORPUS_SIZE);
552 0           cqi_send_string($subcorpus);
553 0           cqi_flush();
554 0           return cqi_expect_int();
555             }
556              
557             # used internally
558             sub cqi_get_field_key {
559 0     0 0   my $field = uc shift;
560 0 0         if ($field =~ /^(MATCH(END)?|TARGET|KEYWORD)$/) {
561 0           return eval "\$CWB::CQI::CONST_FIELD_$field";
562             }
563             else {
564 0           return undef;
565             }
566             }
567              
568             sub cqi_subcorpus_has_field {
569 0     0 0   my ($subcorpus, $field) = @_;
570 0 0 0       croak "USAGE: \$ok = cqi_subcorpus_has_field(\$subcorpus, 'match'|'matchend'|'target'|'keyword');"
571             unless @_ == 2 and defined (my $field_key = cqi_get_field_key($field));
572 0           $LastCmd = "CQI_CQP_SUBCORPUS_HAS_FIELD($subcorpus, CQI_CONST_FIELD_".(uc $field).")";
573 0           cqi_send_word($CWB::CQI::CQP_SUBCORPUS_HAS_FIELD);
574 0           cqi_send_string($subcorpus);
575 0           cqi_send_byte($field_key);
576 0           cqi_flush();
577 0           return cqi_expect_bool();
578             }
579              
580             sub cqi_dump_subcorpus {
581 0     0 0   my ($subcorpus, $field, $first, $last) = @_;
582 0 0 0       croak "USAGE: \@column = cqi_dump_subcorpus(\$subcorpus, 'match'|'matchend'|'target'|'keyword', \$from, \$to);"
583             unless @_ == 4 and defined (my $field_key = cqi_get_field_key($field));
584 0           $LastCmd = "CQI_CQP_DUMP_SUBCORPUS($subcorpus, CQI_CONST_FIELD_".(uc $field).", $first, $last)";
585 0           cqi_send_word($CWB::CQI::CQP_DUMP_SUBCORPUS);
586 0           cqi_send_string($subcorpus);
587 0           cqi_send_byte($field_key);
588 0           cqi_send_int($first);
589 0           cqi_send_int($last);
590 0           cqi_flush();
591 0           return cqi_expect_int_list();
592             }
593              
594             sub cqi_drop_subcorpus {
595 0     0 0   my $subcorpus = shift;
596 0           $LastCmd = "CQI_CQP_DROP_SUBCORPUS($subcorpus)";
597 0           cqi_send_word($CWB::CQI::CQP_DROP_SUBCORPUS);
598 0           cqi_send_string($subcorpus);
599 0           cqi_flush();
600 0           cqi_expect_status($CWB::CQI::STATUS_OK);
601             }
602              
603             ## cqi_fdist() subsumes both cqi_fdist_1() and cqi_fdist_2()
604             ## returns list of (id, f) or (id1, id2, f) tuples as hashref's
605             sub cqi_fdist {
606 0     0 0   my $subcorpus = shift;
607 0           my $cutoff = shift;
608 0           my $key1 = shift;
609 0           my $key2 = shift;
610 0           my ($field1, $field2, $att1, $att2, $tmp);
611 0           ($tmp, $att1) = split /\./, $key1;
612 0           $field1 = cqi_get_field_key($tmp);
613 0 0         if (defined $key2) {
614 0           ($tmp, $att2) = split /\./, $key2;
615 0           $field2 = cqi_get_field_key($tmp);
616             }
617             else {
618 0           $field2 = "";
619 0           $att2 = "x";
620             }
621 0 0 0       croak "USAGE: \@table = cqi_fdist(\$subcorpus, \$cutoff, \$key1 [, \$key2]);"
      0        
      0        
      0        
      0        
      0        
      0        
622             unless @_ == 0 and defined $field1 and defined $field2 and defined $att1 and defined $att2
623             and $att1 =~ /^[a-z]+$/ and $att2 =~ /^[a-z]+$/ and $cutoff >= 0;
624 0 0         if ($field2 ne "") {
625 0           $LastCmd = "CQI_CQP_FDIST_2($subcorpus, $cutoff, $key1, $key2)";
626 0           cqi_send_word($CWB::CQI::CQP_FDIST_2);
627 0           cqi_send_string($subcorpus);
628 0           cqi_send_int($cutoff);
629 0           cqi_send_byte($field1);
630 0           cqi_send_string($att1);
631 0           cqi_send_byte($field2);
632 0           cqi_send_string($att2);
633 0           cqi_flush();
634 0           return cqi_expect_int_table();
635             }
636             else {
637 0           $LastCmd = "CQI_CQP_FDIST_1($subcorpus, $cutoff, $key1)";
638 0           cqi_send_word($CWB::CQI::CQP_FDIST_1);
639 0           cqi_send_string($subcorpus);
640 0           cqi_send_int($cutoff);
641 0           cqi_send_byte($field1);
642 0           cqi_send_string($att1);
643 0           cqi_flush();
644 0           return cqi_expect_int_table();
645             }
646             }
647              
648              
649             #
650             #
651             # CQi expect response / data
652             #
653             #
654             sub cqi_expect_byte {
655 0     0 0   my $r = cqi_read_word();
656 0           CqiCheckResponse $r, $CWB::CQI::DATA_BYTE;
657 0           return cqi_read_byte();
658             }
659              
660             sub cqi_expect_bool {
661 0     0 0   my $r = cqi_read_word();
662 0           CqiCheckResponse $r, $CWB::CQI::DATA_BOOL;
663 0           return cqi_read_byte();
664             }
665              
666             sub cqi_expect_int {
667 0     0 0   my $r = cqi_read_word();
668 0           CqiCheckResponse $r, $CWB::CQI::DATA_INT;
669 0           return cqi_read_int();
670             }
671              
672             sub cqi_expect_string {
673 0     0 0   my $r = cqi_read_word();
674 0           CqiCheckResponse $r, $CWB::CQI::DATA_STRING;
675 0           return cqi_read_string();
676             }
677              
678             sub cqi_expect_byte_list {
679 0     0 0   my $r = cqi_read_word();
680 0           CqiCheckResponse $r, $CWB::CQI::DATA_BYTE_LIST;
681 0           return cqi_read_byte_list();
682             }
683              
684             sub cqi_expect_bool_list {
685 0     0 0   my $r = cqi_read_word();
686 0           CqiCheckResponse $r, $CWB::CQI::DATA_BOOL_LIST;
687 0           return cqi_read_byte_list();
688             }
689              
690             sub cqi_expect_int_list {
691 0     0 0   my $r = cqi_read_word();
692 0           CqiCheckResponse $r, $CWB::CQI::DATA_INT_LIST;
693 0           return cqi_read_int_list();
694             }
695              
696             sub cqi_expect_string_list {
697 0     0 0   my $r = cqi_read_word();
698 0           CqiCheckResponse $r, $CWB::CQI::DATA_STRING_LIST;
699 0           return cqi_read_string_list();
700             }
701              
702             sub cqi_expect_int_int {
703 0     0 0   my $r = cqi_read_word();
704 0           CqiCheckResponse $r, $CWB::CQI::DATA_INT_INT;
705 0           return cqi_read_int(), cqi_read_int();
706             }
707              
708             sub cqi_expect_int_int_int_int {
709 0     0 0   my $r = cqi_read_word();
710 0           CqiCheckResponse $r, $CWB::CQI::DATA_INT_INT_INT_INT;
711 0           return cqi_read_int(), cqi_read_int(), cqi_read_int(), cqi_read_int();
712             }
713              
714             sub cqi_expect_int_table {
715 0     0 0   my $r = cqi_read_word();
716 0           CqiCheckResponse $r, $CWB::CQI::DATA_INT_TABLE;
717 0           return cqi_read_int_table();
718             }
719              
720             sub cqi_expect_status {
721 0     0 0   my @expected = @_; # arguments are list of acceptable responses
722 0           my $r = cqi_read_word();
723 0           CqiCheckResponse $r, @expected;
724 0           return $r;
725             }
726              
727              
728             #
729             #
730             # Internal subroutines (read / write)
731             #
732             #
733             sub cqi_send_byte ($) {
734 0 0   0 0   $conn->print((pack "C", shift))
735             or croak "cqi_send_byte(): $!";
736             }
737              
738             sub cqi_send_word ($) {
739 0 0   0 0   $conn->print((pack "n", shift))
740             or croak "cqi_send_word(): $!";
741             }
742              
743             sub cqi_send_int ($) {
744 0     0 0   my $number = shift; # safely convert native int to 32bit value
745 0           $number = unpack "L", (pack "l", $number); # pack 32bit signed, unpack unsigned -> uses type which can hold unsigned 32bit value
746 0 0         $conn->print(pack("N", $number)) # 'N' packs unsigned 32bit integer
747             or croak "cqi_send_int(): $!";
748             }
749              
750             sub cqi_send_string ($) {
751 0     0 0   my $str = shift;
752 0 0         $conn->print((pack "n", length $str), $str)
753             or croak "cqi_send_str(): $!";
754             }
755              
756             sub cqi_send_byte_list (@) {
757 0     0 0   cqi_send_int(scalar @_);
758 0           map {cqi_send_byte($_)} @_;
  0            
759             }
760              
761             sub cqi_send_word_list (@) {
762 0     0 0   cqi_send_int(scalar @_);
763 0           map {cqi_send_word($_)} @_;
  0            
764             }
765              
766             sub cqi_send_int_list (@) {
767 0     0 0   cqi_send_int(scalar @_);
768 0           map {cqi_send_int($_)} @_;
  0            
769             }
770              
771             sub cqi_send_string_list (@) {
772 0     0 0   cqi_send_int(scalar @_);
773 0           map {cqi_send_string($_)} @_;
  0            
774             }
775              
776             sub cqi_flush () {
777 0 0   0 0   $conn->flush
778             or croak "cqi_flush(): $!";
779             }
780              
781             sub cqi_read_byte () {
782 0     0 0   my $msg;
783 0 0         croak "cqi_read_byte(): $!"
784             unless defined recv $conn, $msg, 1, MSG_WAITALL;
785 0           return unpack "C", $msg;
786             }
787              
788             sub cqi_read_word () {
789 0     0 0   my $msg;
790 0 0         croak "cqi_read_word(): $!"
791             unless defined recv $conn, $msg, 2, MSG_WAITALL;
792 0           return unpack "N", "\x00\x00$msg"; # this should safely unpack an unsigned short
793             }
794              
795             sub cqi_read_int () {
796 0     0 0   my $msg;
797             my $number;
798            
799 0 0         croak "cqi_read_int(): $!"
800             unless defined recv $conn, $msg, 4, MSG_WAITALL;
801 0           $number = unpack "N", $msg; # unpack seems to default to unsigned
802 0           $number = unpack "l", (pack "L", $number); # convert unsigned 32bit to internal signed int *phew*
803 0           return $number;
804             }
805              
806             sub cqi_read_string () {
807 0     0 0   my ($msg, $len);
808 0           $len = cqi_read_word();
809 0 0         croak "cqi_read_string(): $!"
810             unless defined recv $conn, $msg, $len, MSG_WAITALL;
811 0           return $msg;
812             }
813              
814             sub cqi_read_byte_list() {
815 0     0 0   my ($i, $len, @list);
816 0           $len = cqi_read_int();
817 0           for ($i = $len; $i > 0; $i--) {
818 0           push @list, cqi_read_byte;
819             }
820 0           return @list;
821             }
822              
823             sub cqi_read_word_list() {
824 0     0 0   my ($i, $len, @list);
825 0           $len = cqi_read_int();
826 0           for ($i = $len; $i > 0; $i--) {
827 0           push @list, cqi_read_word();
828             }
829 0           return @list;
830             }
831              
832             sub cqi_read_int_list() {
833 0     0 0   my ($i, $len, @list);
834 0           $len = cqi_read_int();
835 0           for ($i = $len; $i > 0; $i--) {
836 0           push @list, cqi_read_int();
837             }
838 0           return @list;
839             }
840              
841             sub cqi_read_string_list() {
842 0     0 0   my ($i, $len, @list);
843 0           $len = cqi_read_int();
844 0           for ($i = $len; $i > 0; $i--) {
845 0           push @list, cqi_read_string();
846             }
847 0           return @list;
848             }
849              
850             sub cqi_read_int_table() {
851 0     0 0   my $rows = cqi_read_int();
852 0           my $columns = cqi_read_int();
853 0           my @table = ();
854 0           for (my $i = 0; $i < $rows; $i++) {
855 0           my @line = ();
856 0           for (my $j = 0; $j < $columns; $j++) {
857 0           push @line, cqi_read_int();
858             }
859 0           push @table, [@line];
860             }
861 0           return @table;
862             }
863              
864              
865             1;
866              
867             __END__