New Z39.50 OID utilities: yaz_oidval_to_z3950oid, yaz_str_to_z3950oid
[yaz-moved-to-github.git] / zutil / pquery.c
1 /*
2  * Copyright (c) 1995-2001, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Log: pquery.c,v $
6  * Revision 1.9  2001-09-24 21:51:56  adam
7  * New Z39.50 OID utilities: yaz_oidval_to_z3950oid, yaz_str_to_z3950oid
8  * and yaz_z3950oid_to_str.
9  *
10  * Revision 1.8  2001/07/19 19:14:53  adam
11  * C++ compile.
12  *
13  * Revision 1.7  2001/05/09 23:31:35  adam
14  * String attribute values for PQF. Proper C-backslash escaping for PQF.
15  *
16  * Revision 1.6  2001/03/07 13:24:40  adam
17  * Member and_not in Z_Operator is kept for backwards compatibility.
18  * Added support for definition of CCL operators in field spec file.
19  *
20  * Revision 1.5  2001/02/21 13:46:54  adam
21  * C++ fixes.
22  *
23  * Revision 1.4  1999/12/21 16:25:20  adam
24  * Fixed handling of default/inherited attributes.
25  *
26  * Revision 1.3  1999/12/20 15:20:13  adam
27  * Implemented ccl_pquery to convert from CCL tree to prefix query.
28  *
29  * Revision 1.2  1999/11/30 13:47:12  adam
30  * Improved installation. Moved header files to include/yaz.
31  *
32  * Revision 1.1  1999/06/08 10:10:16  adam
33  * New sub directory zutil. Moved YAZ Compiler to be part of YAZ tree.
34  *
35  * Revision 1.22  1999/04/20 09:56:49  adam
36  * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
37  * Modified all encoders/decoders to reflect this change.
38  *
39  * Revision 1.21  1998/10/13 16:03:37  adam
40  * Better checking for invalid OID's in p_query_rpn.
41  *
42  * Revision 1.20  1998/03/31 15:13:20  adam
43  * Development towards compiled ASN.1.
44  *
45  * Revision 1.19  1998/03/05 08:09:03  adam
46  * Minor change to make C++ happy.
47  *
48  * Revision 1.18  1998/02/11 11:53:36  adam
49  * Changed code so that it compiles as C++.
50  *
51  * Revision 1.17  1997/11/24 11:33:57  adam
52  * Using function odr_nullval() instead of global ODR_NULLVAL when
53  * appropriate.
54  *
55  * Revision 1.16  1997/09/29 13:19:00  adam
56  * Added function, oid_ent_to_oid, to replace the function
57  * oid_getoidbyent, which is not thread safe.
58  *
59  * Revision 1.15  1997/09/29 07:13:43  adam
60  * Changed type of a few variables to avoid warnings.
61  *
62  * Revision 1.14  1997/09/22 12:33:41  adam
63  * Fixed bug introduced by previous commit.
64  *
65  * Revision 1.13  1997/09/17 12:10:42  adam
66  * YAZ version 1.4.
67  *
68  * Revision 1.12  1997/09/01 08:54:13  adam
69  * New windows NT/95 port using MSV5.0. Made prefix query handling
70  * thread safe. The function options ignores empty arguments when met.
71  *
72  * Revision 1.11  1996/11/11 13:15:29  adam
73  * Added proximity operator.
74  *
75  * Revision 1.10  1996/08/12 14:10:35  adam
76  * New function p_query_attset to define default attribute set.
77  *
78  * Revision 1.9  1996/03/15  11:03:46  adam
79  * Attribute set can be set globally for a query with the @attrset
80  * operator. The @attr operator has an optional attribute-set specifier
81  * that sets the attribute set locally.
82  *
83  * Revision 1.8  1996/01/02  11:46:56  quinn
84  * Changed 'operator' to 'roperator' to avoid C++ conflict.
85  *
86  * Revision 1.7  1995/09/29  17:12:36  quinn
87  * Smallish
88  *
89  * Revision 1.6  1995/09/27  15:03:03  quinn
90  * Modified function heads & prototypes.
91  *
92  * Revision 1.5  1995/06/15  12:31:02  quinn
93  * *** empty log message ***
94  *
95  * Revision 1.4  1995/06/15  07:45:19  quinn
96  * Moving to v3.
97  *
98  * Revision 1.3  1995/06/14  11:06:35  adam
99  * Bug fix: Attributes wasn't interpreted correctly!
100  *
101  * Revision 1.2  1995/05/26  08:56:11  adam
102  * New function: p_query_scan.
103  *
104  * Revision 1.1  1995/05/22  15:31:49  adam
105  * New function, p_query_rpn, to convert from prefix (ascii) to rpn (asn).
106  *
107  */
108
109 #include <stdio.h>
110 #include <string.h>
111 #include <stdlib.h>
112
113 #include <yaz/proto.h>
114 #include <yaz/oid.h>
115 #include <yaz/pquery.h>
116
117 static oid_value p_query_dfset = VAL_NONE;
118
119 struct lex_info {
120     const char *query_buf;
121     const char *lex_buf;
122     size_t lex_len;
123     int query_look;
124     char *left_sep;
125     char *right_sep;
126     int escape_char;
127     int term_type;
128 };
129
130 static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o, oid_proto, 
131                                       int num_attr, int max_attr, 
132                                       int *attr_list, char **attr_clist,
133                                       oid_value *attr_set);
134
135 static enum oid_value query_oid_getvalbyname (struct lex_info *li)
136 {
137     enum oid_value value;
138     char buf[32];
139
140     if (li->lex_len > 31)
141         return VAL_NONE;
142     memcpy (buf, li->lex_buf, li->lex_len);
143     buf[li->lex_len] = '\0';
144     value = oid_getvalbyname (buf);
145     return value;
146 }
147
148 static int compare_term (struct lex_info *li, const char *src, size_t off)
149 {
150     size_t len=strlen(src);
151
152     if (li->lex_len == len+off && !memcmp (li->lex_buf+off, src, len-off))
153         return 1;
154     return 0;
155 }
156
157 static int query_token (struct lex_info *li)
158 {
159     int sep_char = ' ';
160     const char *sep_match;
161     const char **qptr = &li->query_buf;
162
163     while (**qptr == ' ')
164         (*qptr)++;
165     if (**qptr == '\0')
166         return 0;
167     li->lex_len = 0;
168     if ((sep_match = strchr (li->left_sep, **qptr)))
169     {
170         sep_char = li->right_sep[sep_match - li->left_sep];
171         ++(*qptr);
172     }
173     li->lex_buf = *qptr;
174     
175     while (**qptr && **qptr != sep_char)
176     {
177         if (**qptr == '\\')
178         {
179             ++(li->lex_len);
180             ++(*qptr);
181         }
182         ++(li->lex_len);
183         ++(*qptr);
184     }
185     if (**qptr)
186         ++(*qptr);
187     if (li->lex_len >= 1 && li->lex_buf[0] == li->escape_char)
188     {
189         if (compare_term (li, "and", 1))
190             return 'a';
191         if (compare_term (li, "or", 1))
192             return 'o';
193         if (compare_term (li, "not", 1))
194             return 'n';
195         if (compare_term (li, "attr", 1))
196             return 'l';
197         if (compare_term (li, "set", 1))
198             return 's';
199         if (compare_term (li, "attrset", 1))
200             return 'r';
201         if (compare_term (li, "prox", 1))
202             return 'p';
203         if (compare_term (li, "term", 1))
204             return 'y';
205     }
206     return 't';
207 }
208
209 static int lex (struct lex_info *li)
210 {
211     return li->query_look = query_token (li);
212 }
213
214 static int escape_string(char *out_buf, const char *in, int len)
215 {
216
217     char *out = out_buf;
218     while (--len >= 0)
219         if (*in == '\\' && len > 0)
220         {
221             --len;
222             switch (*++in)
223             {
224             case 't':
225                 *out++ = '\t';
226                 break;
227             case 'n':
228                 *out++ = '\n';
229                 break;
230             case 'r':
231                 *out++ = '\r';
232                 break;
233             case 'f':
234                 *out++ = '\f';
235                 break;
236             case 'x':
237                 if (len > 1)
238                 {
239                     char s[4];
240                     int n = 0;
241                     s[0] = *++in;
242                     s[1] = *++in;
243                     s[2] = '\0';
244                     len = len - 2;
245                     sscanf (s, "%x", &n);
246                     *out++ = n;
247                 }
248                 break;
249             case '0':
250             case '1':
251             case '2':
252             case '3':
253                 if (len > 1)
254                 {
255                     char s[4];
256                     int n = 0;
257                     s[0] = *in;
258                     s[1] = *++in;                   
259                     s[2] = *++in;
260                     s[3] = '\0';
261                     len = len - 2;
262                     sscanf (s, "%o", &n);
263                     *out++ = n;
264                 }
265                 break;
266             default:
267                 *out++ = *in;
268                 break;
269             }
270             in++;
271         }
272         else
273             *out++ = *in++;
274     return out - out_buf;
275 }
276
277 static int p_query_parse_attr(struct lex_info *li, ODR o,
278                               int num_attr, int *attr_list,
279                               char **attr_clist, oid_value *attr_set)
280 {
281     const char *cp;
282     if (!(cp = strchr (li->lex_buf, '=')) ||
283         (size_t) (cp-li->lex_buf) > li->lex_len)
284     {
285         attr_set[num_attr] = query_oid_getvalbyname (li);
286         if (attr_set[num_attr] == VAL_NONE)
287             return 0;
288         lex (li);
289         
290         if (!(cp = strchr (li->lex_buf, '=')))
291             return 0;
292     }
293     else 
294     {
295         if (num_attr > 0)
296             attr_set[num_attr] = attr_set[num_attr-1];
297         else
298             attr_set[num_attr] = VAL_NONE;
299     }
300     attr_list[2*num_attr] = atoi(li->lex_buf);
301         cp++;
302     if (*cp >= '0' && *cp <= '9')
303     {
304         attr_list[2*num_attr+1] = atoi (cp);
305         attr_clist[num_attr] = 0;
306     }
307     else
308     {
309         int len = li->lex_len - (cp - li->lex_buf);
310         attr_list[2*num_attr+1] = 0;
311         attr_clist[num_attr] = (char *) odr_malloc (o, len+1);
312         len = escape_string(attr_clist[num_attr], cp, len);
313         attr_clist[num_attr][len] = '\0';
314     }
315     return 1;
316 }
317
318 static Z_AttributesPlusTerm *rpn_term (struct lex_info *li, ODR o,
319                                        oid_proto proto, 
320                                        int num_attr, int *attr_list,
321                                        char **attr_clist, oid_value *attr_set)
322 {
323     Z_AttributesPlusTerm *zapt;
324     Odr_oct *term_octet;
325     Z_Term *term;
326     Z_AttributeElement **elements;
327
328     zapt = (Z_AttributesPlusTerm *)odr_malloc (o, sizeof(*zapt));
329     term_octet = (Odr_oct *)odr_malloc (o, sizeof(*term_octet));
330     term = (Z_Term *)odr_malloc (o, sizeof(*term));
331
332     if (!num_attr)
333         elements = (Z_AttributeElement**)odr_nullval();
334     else
335     {
336         int i, k = 0;
337         int *attr_tmp;
338
339         elements = (Z_AttributeElement**)
340             odr_malloc (o, num_attr * sizeof(*elements));
341
342         attr_tmp = (int *)odr_malloc (o, num_attr * 2 * sizeof(int));
343         memcpy (attr_tmp, attr_list, num_attr * 2 * sizeof(int));
344         for (i = num_attr; --i >= 0; )
345         {
346             int j;
347             for (j = i+1; j<num_attr; j++)
348                 if (attr_tmp[2*j] == attr_tmp[2*i])
349                     break;
350             if (j < num_attr)
351                 continue;
352             elements[k] =
353                 (Z_AttributeElement*)odr_malloc (o,sizeof(**elements));
354             elements[k]->attributeType = &attr_tmp[2*i];
355             elements[k]->attributeSet =
356                 yaz_oidval_to_z3950oid(o, attr_set[i], CLASS_ATTSET);
357             if (attr_clist[i])
358             {
359                 elements[k]->which = Z_AttributeValue_complex;
360                 elements[k]->value.complex = (Z_ComplexAttribute *)
361                     odr_malloc (o, sizeof(Z_ComplexAttribute));
362                 elements[k]->value.complex->num_list = 1;
363                 elements[k]->value.complex->list =
364                     (Z_StringOrNumeric **)
365                     odr_malloc (o, 1 * sizeof(Z_StringOrNumeric *));
366                 elements[k]->value.complex->list[0] =
367                     (Z_StringOrNumeric *)
368                     odr_malloc (o, sizeof(Z_StringOrNumeric));
369                 elements[k]->value.complex->list[0]->which =
370                     Z_StringOrNumeric_string;
371                 elements[k]->value.complex->list[0]->u.string =
372                     attr_clist[i];
373                 elements[k]->value.complex->semanticAction = (int **)
374                     odr_nullval();
375                 elements[k]->value.complex->num_semanticAction = 0;
376             }
377             else
378             {
379                 elements[k]->which = Z_AttributeValue_numeric;
380                 elements[k]->value.numeric = &attr_tmp[2*i+1];
381             }
382             k++;
383         }
384         num_attr = k;
385     }
386 #ifdef ASN_COMPILED
387     zapt->attributes = (Z_AttributeList *)
388         odr_malloc (o, sizeof(*zapt->attributes));
389     zapt->attributes->num_attributes = num_attr;
390     zapt->attributes->attributes = elements;
391 #else
392     zapt->num_attributes = num_attr;
393     zapt->attributeList = elements;
394 #endif    
395
396     zapt->term = term;
397     term->which = Z_Term_general;
398     term->u.general = term_octet;
399     term_octet->buf = (unsigned char *)odr_malloc (o, li->lex_len);
400     term_octet->size = term_octet->len =
401         escape_string ((char *) (term_octet->buf), li->lex_buf, li->lex_len);
402     return zapt;
403 }
404
405 static Z_Operand *rpn_simple (struct lex_info *li, ODR o, oid_proto proto,
406                               int num_attr, int *attr_list, char **attr_clist,
407                               oid_value *attr_set)
408 {
409     Z_Operand *zo;
410
411     zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
412     switch (li->query_look)
413     {
414     case 't':
415         zo->which = Z_Operand_APT;
416         if (!(zo->u.attributesPlusTerm =
417               rpn_term (li, o, proto, num_attr, attr_list, attr_clist,
418                         attr_set)))
419             return NULL;
420         lex (li);
421         break;
422     case 's':
423         lex (li);
424         if (!li->query_look)
425             return NULL;
426         zo->which = Z_Operand_resultSetId;
427         zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
428         memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
429         zo->u.resultSetId[li->lex_len] = '\0';
430         lex (li);
431         break;
432     default:
433         return NULL;
434     }
435     return zo;
436 }
437
438 static Z_ProximityOperator *rpn_proximity (struct lex_info *li, ODR o)
439 {
440     Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
441
442     if (!lex (li))
443         return NULL;
444     if (*li->lex_buf == '1')
445     {
446         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
447         *p->exclusion = 1;
448     } 
449     else if (*li->lex_buf == '0')
450     {
451         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
452         *p->exclusion = 0;
453     }
454     else
455         p->exclusion = NULL;
456
457     if (!lex (li))
458         return NULL;
459     p->distance = (int *)odr_malloc (o, sizeof(*p->distance));
460     *p->distance = atoi (li->lex_buf);
461
462     if (!lex (li))
463         return NULL;
464     p->ordered = (int *)odr_malloc (o, sizeof(*p->ordered));
465     *p->ordered = atoi (li->lex_buf);
466     
467     if (!lex (li))
468         return NULL;
469     p->relationType = (int *)odr_malloc (o, sizeof(*p->relationType));
470     *p->relationType = atoi (li->lex_buf);
471
472     if (!lex (li))
473         return NULL;
474     if (*li->lex_buf == 'k')
475         p->which = 0;
476     else if (*li->lex_buf == 'p')
477         p->which = 1;
478     else
479         p->which = atoi (li->lex_buf);
480
481     if (!lex (li))
482         return NULL;
483 #ifdef ASN_COMPILED
484     p->which = Z_ProximityOperator_known;
485     p->u.known = (int *)odr_malloc (o, sizeof(*p->u.known));
486     *p->u.known = atoi (li->lex_buf);
487 #else
488     p->proximityUnitCode = (int *)odr_malloc (o, sizeof(*p->proximityUnitCode));
489     *p->proximityUnitCode = atoi (li->lex_buf);
490 #endif
491     return p;
492 }
493
494 static Z_Complex *rpn_complex (struct lex_info *li, ODR o, oid_proto proto,
495                                int num_attr, int max_attr, 
496                                int *attr_list, char **attr_clist,
497                                oid_value *attr_set)
498 {
499     Z_Complex *zc;
500     Z_Operator *zo;
501
502     zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
503     zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
504     zc->roperator = zo;
505     switch (li->query_look)
506     {
507     case 'a':
508         zo->which = Z_Operator_and;
509         zo->u.and_not = odr_nullval();
510         break;
511     case 'o':
512         zo->which = Z_Operator_or;
513         zo->u.and_not = odr_nullval();
514         break;
515     case 'n':
516         zo->which = Z_Operator_and_not;
517         zo->u.and_not = odr_nullval();
518         break;
519     case 'p':
520         zo->which = Z_Operator_prox;
521         zo->u.prox = rpn_proximity (li, o);
522         if (!zo->u.prox)
523             return NULL;
524         break;
525     default:
526         return NULL;
527     }
528     lex (li);
529     if (!(zc->s1 =
530           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
531                          attr_clist, attr_set)))
532         return NULL;
533     if (!(zc->s2 =
534           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
535                          attr_clist, attr_set)))
536         return NULL;
537     return zc;
538 }
539
540 static Z_RPNStructure *rpn_structure (struct lex_info *li, ODR o,
541                                       oid_proto proto, 
542                                       int num_attr, int max_attr, 
543                                       int *attr_list,
544                                       char **attr_clist,
545                                       oid_value *attr_set)
546 {
547     Z_RPNStructure *sz;
548
549     sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
550     switch (li->query_look)
551     {
552     case 'a':
553     case 'o':
554     case 'n':
555     case 'p':
556         sz->which = Z_RPNStructure_complex;
557         if (!(sz->u.complex =
558               rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
559                            attr_clist, attr_set)))
560             return NULL;
561         break;
562     case 't':
563     case 's':
564         sz->which = Z_RPNStructure_simple;
565         if (!(sz->u.simple =
566               rpn_simple (li, o, proto, num_attr, attr_list,
567                           attr_clist, attr_set)))
568             return NULL;
569         break;
570     case 'l':
571         lex (li);
572         if (!li->query_look)
573             return NULL;
574         if (num_attr >= max_attr)
575             return NULL;
576         p_query_parse_attr(li, o, num_attr, attr_list, attr_clist, attr_set);
577         num_attr++;
578         lex (li);
579         return
580             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
581                            attr_clist,  attr_set);
582     case 'y':
583         lex (li);
584         if (!li->query_look)
585             return NULL;
586         if (compare_term (li, "general", 0))
587             li->term_type = Z_Term_general;
588         else if (compare_term (li, "numeric", 0))
589             li->term_type = Z_Term_numeric;
590         else if (compare_term (li, "string", 0))
591             li->term_type = Z_Term_characterString;
592         else if (compare_term (li, "oid", 0))
593             li->term_type = Z_Term_oid;
594         else if (compare_term (li, "datetime", 0))
595             li->term_type = Z_Term_dateTime;
596         else if (compare_term (li, "null", 0))
597             li->term_type = Z_Term_null;
598         lex (li);
599         return
600             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
601                            attr_clist, attr_set);
602     case 0:                /* operator/operand expected! */
603         return NULL;
604     }
605     return sz;
606 }
607
608 Z_RPNQuery *p_query_rpn_mk (ODR o, struct lex_info *li, oid_proto proto,
609                             const char *qbuf)
610 {
611     Z_RPNQuery *zq;
612     int attr_array[1024];
613     char *attr_clist[512];
614     oid_value attr_set[512];
615     oid_value topSet = VAL_NONE;
616
617     zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
618     lex (li);
619     if (li->query_look == 'r')
620     {
621         lex (li);
622         topSet = query_oid_getvalbyname (li);
623         if (topSet == VAL_NONE)
624             return NULL;
625
626         lex (li);
627     }
628     if (topSet == VAL_NONE)
629         topSet = p_query_dfset;
630     if (topSet == VAL_NONE)
631         topSet = VAL_BIB1;
632
633     zq->attributeSetId = yaz_oidval_to_z3950oid(o, CLASS_ATTSET, topSet);
634
635     if (!zq->attributeSetId)
636         return 0;
637
638     if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
639                                             attr_array, attr_clist, attr_set)))
640         return NULL;
641     return zq;
642 }
643
644 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto,
645                          const char *qbuf)
646 {
647     struct lex_info li;
648     
649     li.left_sep = "{\"";
650     li.right_sep = "}\"";
651     li.escape_char = '@';
652     li.term_type = Z_Term_general;
653     li.query_buf = qbuf;
654     return p_query_rpn_mk (o, &li, proto, qbuf);
655 }
656
657
658 Z_AttributesPlusTerm *p_query_scan_mk (struct lex_info *li,
659                                        ODR o, oid_proto proto,
660                                        Odr_oid **attributeSetP,
661                                        const char *qbuf)
662 {
663     int attr_list[1024];
664     char *attr_clist[512];
665     oid_value attr_set[512];
666     int num_attr = 0;
667     int max_attr = 512;
668     oid_value topSet = VAL_NONE;
669
670     lex (li);
671     if (li->query_look == 'r')
672     {
673         lex (li);
674         topSet = query_oid_getvalbyname (li);
675
676         lex (li);
677     }
678     if (topSet == VAL_NONE)
679         topSet = p_query_dfset;
680     if (topSet == VAL_NONE)
681         topSet = VAL_BIB1;
682
683     *attributeSetP = yaz_oidval_to_z3950oid (o, CLASS_ATTSET, topSet);
684
685     while (li->query_look == 'l')
686     {
687         lex (li);
688         if (!li->query_look)
689             return NULL;
690         if (num_attr >= max_attr)
691             return NULL;
692         p_query_parse_attr(li, o, num_attr, attr_list, attr_clist, attr_set);
693         num_attr++;
694         lex (li);
695     }
696     if (!li->query_look)
697         return NULL;
698     return rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
699 }
700
701 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
702                                     Odr_oid **attributeSetP,
703                                     const char *qbuf)
704 {
705     struct lex_info li;
706
707     li.left_sep = "{\"";
708     li.right_sep = "}\"";
709     li.escape_char = '@';
710     li.term_type = Z_Term_general;
711     li.query_buf = qbuf;
712
713     return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
714 }
715
716 int p_query_attset (const char *arg)
717 {
718     p_query_dfset = oid_getvalbyname (arg);
719     return (p_query_dfset == VAL_NONE) ? -1 : 0;
720 }
721