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