Added proximity operator.
[yaz-moved-to-github.git] / util / pquery.c
1 /*
2  * Copyright (c) 1995-1996, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: pquery.c,v $
7  * Revision 1.11  1996-11-11 13:15:29  adam
8  * Added proximity operator.
9  *
10  * Revision 1.10  1996/08/12 14:10:35  adam
11  * New function p_query_attset to define default attribute set.
12  *
13  * Revision 1.9  1996/03/15  11:03:46  adam
14  * Attribute set can be set globally for a query with the @attrset
15  * operator. The @attr operator has an optional attribute-set specifier
16  * that sets the attribute set locally.
17  *
18  * Revision 1.8  1996/01/02  11:46:56  quinn
19  * Changed 'operator' to 'roperator' to avoid C++ conflict.
20  *
21  * Revision 1.7  1995/09/29  17:12:36  quinn
22  * Smallish
23  *
24  * Revision 1.6  1995/09/27  15:03:03  quinn
25  * Modified function heads & prototypes.
26  *
27  * Revision 1.5  1995/06/15  12:31:02  quinn
28  * *** empty log message ***
29  *
30  * Revision 1.4  1995/06/15  07:45:19  quinn
31  * Moving to v3.
32  *
33  * Revision 1.3  1995/06/14  11:06:35  adam
34  * Bug fix: Attributes wasn't interpreted correctly!
35  *
36  * Revision 1.2  1995/05/26  08:56:11  adam
37  * New function: p_query_scan.
38  *
39  * Revision 1.1  1995/05/22  15:31:49  adam
40  * New function, p_query_rpn, to convert from prefix (ascii) to rpn (asn).
41  *
42  */
43
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47
48 #include <proto.h>
49 #include <oid.h>
50
51 #include <pquery.h>
52
53 static oid_value p_query_dfset = VAL_NONE;
54
55 static const char *query_buf;
56 static const char *query_lex_buf;
57 static int query_lex_len;
58 static int query_look = 0;
59 static char *left_sep = "{\"";
60 static char *right_sep = "}\"";
61 static int escape_char = '@';
62
63 static Z_RPNStructure *rpn_structure (ODR o, oid_proto, 
64                                       int num_attr, int max_attr, 
65                                       int *attr_list, oid_value *attr_set);
66
67 static int query_oid_getvalbyname (void)
68 {
69     char buf[32];
70
71     if (query_lex_len > 31)
72         return VAL_NONE;
73     memcpy (buf, query_lex_buf, query_lex_len);
74     buf[query_lex_len] = '\0';
75     return oid_getvalbyname (buf);
76 }
77
78 static int query_token (const char **qptr, const char **lex_buf, int *lex_len)
79 {
80     const char *sep_match;
81
82     while (**qptr == ' ')
83         (*qptr)++;
84     if (**qptr == '\0')
85         return 0;
86     *lex_len = 0;
87     if ((sep_match = strchr (left_sep, **qptr)))
88     {
89         int sep_index = sep_match - left_sep;
90         
91         ++(*qptr);
92         *lex_buf = *qptr;
93         while (**qptr && **qptr != right_sep[sep_index])
94         {
95             ++(*lex_len);
96             ++(*qptr);
97         }
98         if (**qptr)
99             ++(*qptr);
100     }
101     else
102     {
103         *lex_buf = *qptr;
104         while (**qptr && **qptr != ' ')
105         {
106             ++(*lex_len);
107             ++(*qptr);
108         }
109     }
110     if (*lex_len >= 1 && (*lex_buf)[0] == escape_char)
111     {
112         if (*lex_len == 4 && !memcmp (*lex_buf+1, "and", 3))
113             return 'a';
114         if (*lex_len == 3 && !memcmp (*lex_buf+1, "or", 2))
115             return 'o';
116         if (*lex_len == 4 && !memcmp (*lex_buf+1, "not", 3))
117             return 'n';
118         if (*lex_len == 5 && !memcmp (*lex_buf+1, "attr", 4))
119             return 'l';
120         if (*lex_len == 4 && !memcmp (*lex_buf+1, "set", 3))
121             return 's';
122         if (*lex_len == 8 && !memcmp (*lex_buf+1, "attrset", 7))
123             return 'r';
124         if (*lex_len == 5 && !memcmp (*lex_buf+1, "prox", 4))
125             return 'p';
126     }
127     return 't';
128 }
129
130 static int lex (void)
131 {
132     return query_look = 
133         query_token (&query_buf, &query_lex_buf, &query_lex_len);
134 }
135
136 static Z_AttributesPlusTerm *rpn_term (ODR o, oid_proto proto, 
137                                        int num_attr, int *attr_list,
138                                        oid_value *attr_set)
139 {
140     Z_AttributesPlusTerm *zapt;
141     Odr_oct *term_octet;
142     Z_Term *term;
143
144     zapt = odr_malloc (o, sizeof(*zapt));
145     term_octet = odr_malloc (o, sizeof(*term_octet));
146     term = odr_malloc (o, sizeof(*term));
147
148     zapt->num_attributes = num_attr;
149     if (num_attr)
150     {
151         int i;
152         int *attr_tmp;
153
154         zapt->attributeList = odr_malloc (o, num_attr * 
155                                           sizeof(*zapt->attributeList));
156
157         attr_tmp = odr_malloc (o, num_attr * 2 * sizeof(int));
158         memcpy (attr_tmp, attr_list, num_attr * 2 * sizeof(int));
159         for (i = 0; i < num_attr; i++)
160         {
161             zapt->attributeList[i] =
162                 odr_malloc (o,sizeof(**zapt->attributeList));
163             zapt->attributeList[i]->attributeType = &attr_tmp[2*i];
164 #ifdef Z_95
165             if (attr_set[i] == VAL_NONE)
166                 zapt->attributeList[i]->attributeSet = 0;
167             else
168             {
169                 oident attrid;
170
171                 attrid.proto = PROTO_Z3950;
172                 attrid.oclass = CLASS_ATTSET;
173                 attrid.value = attr_set[i];
174                    
175                 zapt->attributeList[i]->attributeSet = 
176                     odr_oiddup (o, oid_getoidbyent (&attrid));
177             }
178             zapt->attributeList[i]->which = Z_AttributeValue_numeric;
179             zapt->attributeList[i]->value.numeric = &attr_tmp[2*i+1];
180 #else
181             zapt->attributeList[i]->attributeValue = &attr_tmp[2*i+1];
182 #endif
183         }
184     }
185     else
186         zapt->attributeList = ODR_NULLVAL;
187     zapt->term = term;
188     term->which = Z_Term_general;
189     term->u.general = term_octet;
190     term_octet->buf = odr_malloc (o, query_lex_len);
191     term_octet->size = term_octet->len = query_lex_len;
192     memcpy (term_octet->buf, query_lex_buf, query_lex_len);
193     return zapt;
194 }
195
196 static Z_Operand *rpn_simple (ODR o, oid_proto proto,
197                               int num_attr, int *attr_list,
198                               oid_value *attr_set)
199 {
200     Z_Operand *zo;
201
202     zo = odr_malloc (o, sizeof(*zo));
203     switch (query_look)
204     {
205     case 't':
206         zo->which = Z_Operand_APT;
207         if (!(zo->u.attributesPlusTerm =
208               rpn_term (o, proto, num_attr, attr_list, attr_set)))
209             return NULL;
210         lex ();
211         break;
212     case 's':
213         lex ();
214         if (!query_look)
215             return NULL;
216         zo->which = Z_Operand_resultSetId;
217         zo->u.resultSetId = odr_malloc (o, query_lex_len+1);
218         memcpy (zo->u.resultSetId, query_lex_buf, query_lex_len);
219         zo->u.resultSetId[query_lex_len] = '\0';
220         lex ();
221         break;
222     default:
223         return NULL;
224     }
225     return zo;
226 }
227
228 static Z_ProximityOperator *rpn_proximity (ODR o)
229 {
230     Z_ProximityOperator *p = odr_malloc (o, sizeof(*p));
231
232     if (!lex ())
233         return NULL;
234     if (*query_lex_buf == '1')
235     {
236         p->exclusion = odr_malloc (o, sizeof(*p->exclusion));
237         *p->exclusion = 1;
238     } 
239     else if (*query_lex_buf == '0')
240     {
241         p->exclusion = odr_malloc (o, sizeof(*p->exclusion));
242         *p->exclusion = 0;
243     }
244     else
245         p->exclusion = NULL;
246
247     if (!lex ())
248         return NULL;
249     p->distance = odr_malloc (o, sizeof(*p->distance));
250     *p->distance = atoi (query_lex_buf);
251
252     if (!lex ())
253         return NULL;
254     p->ordered = odr_malloc (o, sizeof(*p->ordered));
255     *p->ordered = atoi (query_lex_buf);
256     
257     if (!lex ())
258         return NULL;
259     p->relationType = odr_malloc (o, sizeof(*p->relationType));
260     *p->relationType = atoi (query_lex_buf);
261
262     if (!lex ())
263         return NULL;
264     if (*query_lex_buf == 'k')
265         p->which = 0;
266     else if (*query_lex_buf == 'p')
267         p->which = 1;
268     else
269         p->which = atoi (query_lex_buf);
270
271     if (!lex ())
272         return NULL;
273     p->proximityUnitCode = odr_malloc (o, sizeof(*p->proximityUnitCode));
274     *p->proximityUnitCode = atoi (query_lex_buf);
275
276     return p;
277 }
278
279 static Z_Complex *rpn_complex (ODR o, oid_proto proto,
280                                int num_attr, int max_attr, 
281                                int *attr_list, oid_value *attr_set)
282 {
283     Z_Complex *zc;
284     Z_Operator *zo;
285
286     zc = odr_malloc (o, sizeof(*zc));
287     zo = odr_malloc (o, sizeof(*zo));
288     zc->roperator = zo;
289     switch (query_look)
290     {
291     case 'a':
292         zo->which = Z_Operator_and;
293         zo->u.and = ODR_NULLVAL;
294         break;
295     case 'o':
296         zo->which = Z_Operator_or;
297         zo->u.and = ODR_NULLVAL;
298         break;
299     case 'n':
300         zo->which = Z_Operator_and_not;
301         zo->u.and = ODR_NULLVAL;
302         break;
303     case 'p':
304         zo->which = Z_Operator_prox;
305         zo->u.prox = rpn_proximity (o);
306         if (!zo->u.prox)
307             return NULL;
308         break;
309     default:
310         return NULL;
311     }
312     lex ();
313     if (!(zc->s1 =
314           rpn_structure (o, proto, num_attr, max_attr, attr_list, attr_set)))
315         return NULL;
316     if (!(zc->s2 =
317           rpn_structure (o, proto, num_attr, max_attr, attr_list, attr_set)))
318         return NULL;
319     return zc;
320 }
321
322 static Z_RPNStructure *rpn_structure (ODR o, oid_proto proto, 
323                                       int num_attr, int max_attr, 
324                                       int *attr_list, oid_value *attr_set)
325 {
326     Z_RPNStructure *sz;
327     const char *cp;
328
329     sz = odr_malloc (o, sizeof(*sz));
330     switch (query_look)
331     {
332     case 'a':
333     case 'o':
334     case 'n':
335     case 'p':
336         sz->which = Z_RPNStructure_complex;
337         if (!(sz->u.complex =
338               rpn_complex (o, proto, num_attr, max_attr, attr_list, attr_set)))
339             return NULL;
340         break;
341     case 't':
342     case 's':
343         sz->which = Z_RPNStructure_simple;
344         if (!(sz->u.simple =
345               rpn_simple (o, proto, num_attr, attr_list, attr_set)))
346             return NULL;
347         break;
348     case 'l':
349         lex ();
350         if (!query_look)
351             return NULL;
352         if (num_attr >= max_attr)
353             return NULL;
354         if (!(cp = strchr (query_lex_buf, '=')) ||
355             (cp-query_lex_buf) > query_lex_len)
356         {
357             attr_set[num_attr] = query_oid_getvalbyname ();
358             lex ();
359
360             if (!(cp = strchr (query_lex_buf, '=')))
361                 return NULL;
362         }
363         else 
364         {
365             if (num_attr > 0)
366                 attr_set[num_attr] = attr_set[num_attr-1];
367             else
368                 attr_set[num_attr] = VAL_NONE;
369         }
370         attr_list[2*num_attr] = atoi (query_lex_buf);
371         attr_list[2*num_attr+1] = atoi (cp+1);
372         num_attr++;
373         lex ();
374         return
375             rpn_structure (o, proto, num_attr, max_attr, attr_list, attr_set);
376     case 0:                /* operator/operand expected! */
377         return NULL;
378     }
379     return sz;
380 }
381
382 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf)
383 {
384     Z_RPNQuery *zq;
385     int attr_array[1024];
386     oid_value attr_set[512];
387     oid_value topSet = VAL_NONE;
388     oident oset;
389
390     query_buf = qbuf;
391     zq = odr_malloc (o, sizeof(*zq));
392     lex ();
393     if (query_look == 'r')
394     {
395         lex ();
396         topSet = query_oid_getvalbyname ();
397         if (topSet == VAL_NONE)
398             return NULL;
399
400         lex ();
401     }
402     if (topSet == VAL_NONE)
403         topSet = p_query_dfset;
404     if (topSet == VAL_NONE)
405         topSet = VAL_BIB1;
406     oset.proto = proto;
407     oset.oclass = CLASS_ATTSET;
408     oset.value = topSet;
409
410     zq->attributeSetId = odr_oiddup (o, oid_getoidbyent (&oset));
411
412     if (!(zq->RPNStructure = rpn_structure (o, proto, 0, 512,
413                                             attr_array, attr_set)))
414         return NULL;
415     return zq;
416 }
417
418 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
419                                     Odr_oid **attributeSetP,
420                                     const char *qbuf)
421 {
422     int attr_list[1024];
423     oid_value attr_set[512];
424     int num_attr = 0;
425     int max_attr = 512;
426     const char *cp;
427     oid_value topSet = VAL_NONE;
428     oident oset;
429
430     query_buf = qbuf;
431
432     lex ();
433     if (query_look == 'r')
434     {
435         lex ();
436         topSet = query_oid_getvalbyname ();
437
438         lex ();
439     }
440     if (topSet == VAL_NONE)
441         topSet = p_query_dfset;
442     if (topSet == VAL_NONE)
443         topSet = VAL_BIB1;
444     oset.proto = proto;
445     oset.oclass = CLASS_ATTSET;
446     oset.value = topSet;
447
448     *attributeSetP = odr_oiddup (o, oid_getoidbyent (&oset));
449
450     while (query_look == 'l')
451     {
452         lex ();
453         if (!query_look)
454             return NULL;
455         if (num_attr >= max_attr)
456             return NULL;
457
458         if (!(cp = strchr (query_lex_buf, '=')) ||
459             (cp-query_lex_buf) > query_lex_len)
460         {
461             attr_set[num_attr] = query_oid_getvalbyname ();
462             lex ();
463
464             if (!(cp = strchr (query_lex_buf, '=')))
465                 return NULL;
466         }
467         else
468         {
469             if (num_attr > 0)
470                 attr_set[num_attr] = attr_set[num_attr-1];
471             else
472                 attr_set[num_attr] = VAL_NONE;
473         }
474         attr_list[2*num_attr] = atoi (query_lex_buf);
475         attr_list[2*num_attr+1] = atoi (cp+1);
476         num_attr++;
477         lex ();
478     }
479     if (!query_look)
480         return NULL;
481     return rpn_term (o, proto, num_attr, attr_list, attr_set);
482 }
483
484 int p_query_attset (const char *arg)
485 {
486     p_query_dfset = oid_getvalbyname (arg);
487     return (p_query_dfset == VAL_NONE) ? -1 : 0;
488 }
489