1 # Perl module for sending queries to Sherlock search servers and parsing answers
3 # (c) 2002 Martin Mares <mj@ucw.cz>
5 # This software may be freely distributed and used according to the terms
6 # of the GNU Lesser General Public License.
8 package Sherlock::Query;
15 sub do_parse_tree($$$$);
20 my $server = shift @_;
33 my $sock = IO::Socket::INET->new(PeerAddr => $q->{SERVER}, Proto => 'tcp')
34 or return "-900 Cannot connect to search server: $!";
35 print $sock $string, "\n";
40 $stat =~ /^[+-]/ or return "-901 Reply parse error";
51 if (!defined $block) {
53 push @{$q->{RAW}}, $block;
96 our $footer_syntax = {
101 my ($q,$string) = @_;
103 # Send the query and gather results
104 my $stat = $q->command($string);
105 my @raw = @{$q->{RAW}};
107 # Split results to header, cards and footer
108 $q->{HEADER} = { RAW => [] };
109 if (@raw) { $q->{HEADER}{RAW} = shift @raw; }
110 elsif (!$stat) { return "-902 Incomplete reply"; }
111 $q->{FOOTER} = { RAW => [] };
112 if (@raw && $raw[@raw-1]->[0] =~ /^\+/) {
113 $q->{FOOTER}{RAW} = pop @raw;
117 push @{$q->{CARDS}}, { RAW => pop @raw };
121 parse_tree($q->{HEADER}, $hdr_syntax);
122 foreach my $c (@{$q->{CARDS}}) {
123 parse_tree($c, $card_syntax);
125 parse_tree($q->{FOOTER}, $footer_syntax);
132 my $syntax = shift @_;
133 do_parse_tree($tree->{RAW}, 0, $tree, $syntax);
136 sub do_parse_tree($$$$) {
139 my $cooked = shift @_;
140 my $syntax = shift @_;
143 $raw->[$i] =~ /^(.)(.*)/;
144 if (!defined($syntax->{$1}) && !defined($syntax->{''})) { return $i; }
145 if (ref $syntax->{$1} eq "ARRAY") {
146 push @{$cooked->{$1}}, $2;
148 } elsif (ref $syntax->{$1} eq "HASH") {
150 push @{$cooked->{$1}}, $block;
151 $i = do_parse_tree($raw, $i, $block, $syntax->{$1});
153 $cooked->{$1} = $2 if !defined($cooked->{$1});
159 sub format_tree($$$) {
160 my ($func, $a, $indent) = @_;
161 if (ref $a eq "ARRAY") {
162 if (@{$a} == 0) { &$func("[]\n"); }
165 foreach my $k (@{$a}) {
167 format_tree($func, $k, "$indent\t");
169 &$func($indent . "]\n");
173 foreach my $k (sort keys %{$a}) {
174 &$func("$indent\t$k => ");
175 format_tree($func, $a->{$k}, "$indent\t");
177 &$func($indent . "}\n");
178 } elsif (defined $a) {
186 my ($q, $func, $what) = @_;
187 format_tree($func, $what, "");
192 format_tree(sub { print $_[0]; }, $q, "");