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