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