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