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