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