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