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