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