da12e21102a66e66eac404075195de2fc90ffb55
[yaz-moved-to-github.git] / src / pquery.c
1 /*
2  * Copyright (C) 1995-2007, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: pquery.c,v 1.9 2007-01-03 08:42:15 adam Exp $
6  */
7 /**
8  * \file pquery.c
9  * \brief Implements PQF parsing
10  */
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15
16 #include <yaz/proto.h>
17 #include <yaz/oid.h>
18 #include <yaz/pquery.h>
19
20 static oid_value p_query_dfset = VAL_NONE;
21
22 struct yaz_pqf_parser {
23     const char *query_buf;
24     const char *query_ptr;
25     const char *lex_buf;
26     size_t lex_len;
27     int query_look;
28     char *left_sep;
29     char *right_sep;
30     int escape_char;
31     int term_type;
32     int external_type;
33     int error;
34 };
35
36 static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
37                                       oid_proto, 
38                                       int num_attr, int max_attr, 
39                                       int *attr_list, char **attr_clist,
40                                       oid_value *attr_set);
41
42 static enum oid_value query_oid_getvalbyname (struct yaz_pqf_parser *li)
43 {
44     enum oid_value value;
45     char buf[32];
46
47     if (li->lex_len > 31)
48         return VAL_NONE;
49     memcpy (buf, li->lex_buf, li->lex_len);
50     buf[li->lex_len] = '\0';
51     value = oid_getvalbyname (buf);
52     return value;
53 }
54
55 static int compare_term (struct yaz_pqf_parser *li, const char *src,
56                          size_t off)
57 {
58     size_t len=strlen(src);
59     
60     if (li->lex_len == len+off && !memcmp (li->lex_buf+off, src, len-off))
61         return 1;
62     return 0;
63 }
64
65 static int query_token (struct yaz_pqf_parser *li)
66 {
67     int sep_char = ' ';
68     const char *sep_match;
69     const char **qptr = &li->query_ptr;
70
71     while (**qptr == ' ')
72         (*qptr)++;
73     if (**qptr == '\0')
74         return 0;
75     li->lex_len = 0;
76     if ((sep_match = strchr (li->left_sep, **qptr)))
77     {
78         sep_char = li->right_sep[sep_match - li->left_sep];
79         ++(*qptr);
80     }
81     li->lex_buf = *qptr;
82    
83     if (**qptr == li->escape_char && isdigit (((const unsigned char *) *qptr)[1]))
84     {
85         ++(li->lex_len);
86         ++(*qptr);
87         return 'l';
88     }
89     while (**qptr && **qptr != sep_char)
90     {
91         if (**qptr == '\\')
92         {
93             ++(li->lex_len);
94             ++(*qptr);
95         }
96         ++(li->lex_len);
97         ++(*qptr);
98     }
99     if (**qptr)
100         ++(*qptr);
101     if (sep_char == ' ' &&
102         li->lex_len >= 1 && li->lex_buf[0] == li->escape_char)
103     {
104         if (compare_term (li, "and", 1))
105             return 'a';
106         if (compare_term (li, "or", 1))
107             return 'o';
108         if (compare_term (li, "not", 1))
109             return 'n';
110         if (compare_term (li, "attr", 1))
111             return 'l';
112         if (compare_term (li, "set", 1))
113             return 's';
114         if (compare_term (li, "attrset", 1))
115             return 'r';
116         if (compare_term (li, "prox", 1))
117             return 'p';
118         if (compare_term (li, "term", 1))
119             return 'y';
120     }
121     return 't';
122 }
123
124 static int lex (struct yaz_pqf_parser *li)
125 {
126     return li->query_look = query_token (li);
127 }
128
129 static int escape_string(char *out_buf, const char *in, int len)
130 {
131
132     char *out = out_buf;
133     while (--len >= 0)
134         if (*in == '\\' && len > 0)
135         {
136             --len;
137             switch (*++in)
138             {
139             case 't':
140                 *out++ = '\t';
141                 break;
142             case 'n':
143                 *out++ = '\n';
144                 break;
145             case 'r':
146                 *out++ = '\r';
147                 break;
148             case 'f':
149                 *out++ = '\f';
150                 break;
151             case 'x':
152                 if (len > 1)
153                 {
154                     char s[4];
155                     int n = 0;
156                     s[0] = *++in;
157                     s[1] = *++in;
158                     s[2] = '\0';
159                     len = len - 2;
160                     sscanf (s, "%x", &n);
161                     *out++ = n;
162                 }
163                 break;
164             case '0':
165             case '1':
166             case '2':
167             case '3':
168                 if (len > 1)
169                 {
170                     char s[4];
171                     int n = 0;
172                     s[0] = *in;
173                     s[1] = *++in;                   
174                     s[2] = *++in;
175                     s[3] = '\0';
176                     len = len - 2;
177                     sscanf (s, "%o", &n);
178                     *out++ = n;
179                 }
180                 break;
181             default:
182                 *out++ = *in;
183                 break;
184             }
185             in++;
186         }
187         else
188             *out++ = *in++;
189     return out - out_buf;
190 }
191
192 static int p_query_parse_attr(struct yaz_pqf_parser *li, ODR o,
193                               int num_attr, int *attr_list,
194                               char **attr_clist, oid_value *attr_set)
195 {
196     const char *cp;
197
198     if (!(cp = strchr (li->lex_buf, '=')) ||
199         (size_t) (cp-li->lex_buf) > li->lex_len)
200     {
201         attr_set[num_attr] = query_oid_getvalbyname (li);
202         if (attr_set[num_attr] == VAL_NONE)
203         {
204             li->error = YAZ_PQF_ERROR_ATTSET;
205             return 0;
206         }
207         if (!lex (li))
208         {
209             li->error = YAZ_PQF_ERROR_MISSING;
210             return 0;
211         }
212         if (!(cp = strchr (li->lex_buf, '=')))
213         {
214             li->error = YAZ_PQF_ERROR_BADATTR;
215             return 0;
216         }
217     }
218     else 
219     {
220         if (num_attr > 0)
221             attr_set[num_attr] = attr_set[num_attr-1];
222         else
223             attr_set[num_attr] = VAL_NONE;
224     }
225     if (*li->lex_buf < '0' || *li->lex_buf > '9')
226     {
227         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
228         return 0;
229     }
230     attr_list[2*num_attr] = atoi(li->lex_buf);
231     cp++;
232     if (*cp >= '0' && *cp <= '9')
233     {
234         attr_list[2*num_attr+1] = atoi (cp);
235         attr_clist[num_attr] = 0;
236     }
237     else
238     {
239         int len = li->lex_len - (cp - li->lex_buf);
240         attr_list[2*num_attr+1] = 0;
241         attr_clist[num_attr] = (char *) odr_malloc (o, len+1);
242         len = escape_string(attr_clist[num_attr], cp, len);
243         attr_clist[num_attr][len] = '\0';
244     }
245     return 1;
246 }
247
248 static Z_AttributesPlusTerm *rpn_term (struct yaz_pqf_parser *li, ODR o,
249                                        oid_proto proto, 
250                                        int num_attr, int *attr_list,
251                                        char **attr_clist, oid_value *attr_set)
252 {
253     Z_AttributesPlusTerm *zapt;
254     Odr_oct *term_octet;
255     Z_Term *term;
256     Z_AttributeElement **elements;
257
258     zapt = (Z_AttributesPlusTerm *)odr_malloc (o, sizeof(*zapt));
259     term_octet = (Odr_oct *)odr_malloc (o, sizeof(*term_octet));
260     term = (Z_Term *)odr_malloc (o, sizeof(*term));
261
262     if (!num_attr)
263         elements = (Z_AttributeElement**)odr_nullval();
264     else
265     {
266         int i, k = 0;
267         int *attr_tmp;
268
269         elements = (Z_AttributeElement**)
270             odr_malloc (o, num_attr * sizeof(*elements));
271
272         attr_tmp = (int *)odr_malloc (o, num_attr * 2 * sizeof(int));
273         memcpy (attr_tmp, attr_list, num_attr * 2 * sizeof(int));
274         for (i = num_attr; --i >= 0; )
275         {
276             int j;
277             for (j = i+1; j<num_attr; j++)
278                 if (attr_tmp[2*j] == attr_tmp[2*i])
279                     break;
280             if (j < num_attr)
281                 continue;
282             elements[k] =
283                 (Z_AttributeElement*)odr_malloc (o,sizeof(**elements));
284             elements[k]->attributeType = &attr_tmp[2*i];
285             elements[k]->attributeSet =
286                 yaz_oidval_to_z3950oid(o, CLASS_ATTSET, attr_set[i]);
287
288             if (attr_clist[i])
289             {
290                 elements[k]->which = Z_AttributeValue_complex;
291                 elements[k]->value.complex = (Z_ComplexAttribute *)
292                     odr_malloc (o, sizeof(Z_ComplexAttribute));
293                 elements[k]->value.complex->num_list = 1;
294                 elements[k]->value.complex->list =
295                     (Z_StringOrNumeric **)
296                     odr_malloc (o, 1 * sizeof(Z_StringOrNumeric *));
297                 elements[k]->value.complex->list[0] =
298                     (Z_StringOrNumeric *)
299                     odr_malloc (o, sizeof(Z_StringOrNumeric));
300                 elements[k]->value.complex->list[0]->which =
301                     Z_StringOrNumeric_string;
302                 elements[k]->value.complex->list[0]->u.string =
303                     attr_clist[i];
304                 elements[k]->value.complex->semanticAction = (int **)
305                     odr_nullval();
306                 elements[k]->value.complex->num_semanticAction = 0;
307             }
308             else
309             {
310                 elements[k]->which = Z_AttributeValue_numeric;
311                 elements[k]->value.numeric = &attr_tmp[2*i+1];
312             }
313             k++;
314         }
315         num_attr = k;
316     }
317     zapt->attributes = (Z_AttributeList *)
318         odr_malloc (o, sizeof(*zapt->attributes));
319     zapt->attributes->num_attributes = num_attr;
320     zapt->attributes->attributes = elements;
321
322     zapt->term = term;
323
324     term_octet->buf = (unsigned char *)odr_malloc (o, 1 + li->lex_len);
325     term_octet->size = term_octet->len =
326         escape_string ((char *) (term_octet->buf), li->lex_buf, li->lex_len);
327     term_octet->buf[term_octet->size] = 0;  /* null terminate */
328     
329     switch (li->term_type)
330     {
331     case Z_Term_general:
332         term->which = Z_Term_general;
333         term->u.general = term_octet;
334         break;
335     case Z_Term_characterString:
336         term->which = Z_Term_characterString;
337         term->u.characterString = (char*) term_octet->buf; 
338                                     /* null terminated above */
339         break;
340     case Z_Term_numeric:
341         term->which = Z_Term_numeric;
342         term->u.numeric = odr_intdup (o, atoi((char*) (term_octet->buf)));
343         break;
344     case Z_Term_null:
345         term->which = Z_Term_null;
346         term->u.null = odr_nullval();
347         break;
348     case Z_Term_external:
349         term->which = Z_Term_external;
350         term->u.external = 0;
351         break;
352     default:
353         term->which = Z_Term_null;
354         term->u.null = odr_nullval();
355         break;
356     }
357     return zapt;
358 }
359
360 static Z_Operand *rpn_simple (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
361                               int num_attr, int *attr_list, char **attr_clist,
362                               oid_value *attr_set)
363 {
364     Z_Operand *zo;
365
366     zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
367     switch (li->query_look)
368     {
369     case 't':
370         zo->which = Z_Operand_APT;
371         if (!(zo->u.attributesPlusTerm =
372               rpn_term (li, o, proto, num_attr, attr_list, attr_clist,
373                         attr_set)))
374             return 0;
375         lex (li);
376         break;
377     case 's':
378         lex (li);
379         if (!li->query_look)
380         {
381             li->error = YAZ_PQF_ERROR_MISSING;
382             return 0;
383         }
384         zo->which = Z_Operand_resultSetId;
385         zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
386         memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
387         zo->u.resultSetId[li->lex_len] = '\0';
388         lex (li);
389         break;
390     default:
391         /* we're only called if one of the above types are seens so
392            this shouldn't happen */
393         li->error = YAZ_PQF_ERROR_INTERNAL;
394         return 0;
395     }
396     return zo;
397 }
398
399 static Z_ProximityOperator *rpn_proximity (struct yaz_pqf_parser *li, ODR o)
400 {
401     Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
402
403     if (!lex (li))
404     {
405         li->error = YAZ_PQF_ERROR_MISSING;
406         return NULL;
407     }
408     if (*li->lex_buf == '1')
409         p->exclusion = odr_intdup (o, 1);
410     else if (*li->lex_buf == '0')
411         p->exclusion = odr_intdup (o, 0);
412     else if (*li->lex_buf == 'v' || *li->lex_buf == 'n')
413         p->exclusion = NULL;
414     else
415     {
416         li->error = YAZ_PQF_ERROR_PROXIMITY;
417         return NULL;
418     }
419
420     if (!lex (li))
421     {
422         li->error = YAZ_PQF_ERROR_MISSING;
423         return NULL;
424     }
425     if (*li->lex_buf >= '0' && *li->lex_buf <= '9')
426         p->distance = odr_intdup (o, atoi (li->lex_buf));
427     else
428     {
429         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
430         return NULL;
431     }
432
433     if (!lex (li))
434     {
435         li->error = YAZ_PQF_ERROR_MISSING;
436         return NULL;
437     }
438     if (*li->lex_buf == '1')
439         p->ordered = odr_intdup (o, 1);
440     else if (*li->lex_buf == '0')
441         p->ordered = odr_intdup (o, 0);
442     else
443     {
444         li->error = YAZ_PQF_ERROR_PROXIMITY;
445         return NULL;
446     }
447     
448     if (!lex (li))
449     {
450         li->error = YAZ_PQF_ERROR_MISSING;
451         return NULL;
452     }
453     if (*li->lex_buf >= '0' && *li->lex_buf <= '9')
454         p->relationType = odr_intdup (o, atoi (li->lex_buf));
455     else
456     {
457         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
458         return NULL;
459     }
460
461     if (!lex (li))
462     {
463         li->error = YAZ_PQF_ERROR_MISSING;
464         return NULL;
465     }
466     if (*li->lex_buf == 'k')
467         p->which = Z_ProximityOperator_known;
468     else if (*li->lex_buf == 'p')
469         p->which = Z_ProximityOperator_private;
470     else
471         p->which = atoi (li->lex_buf);
472
473     if (p->which != Z_ProximityOperator_known
474         && p->which != Z_ProximityOperator_private)
475     {
476         li->error = YAZ_PQF_ERROR_PROXIMITY;
477         return NULL;
478     }
479
480     if (!lex (li))
481     {
482         li->error = YAZ_PQF_ERROR_MISSING;
483         return NULL;
484     }
485     if (*li->lex_buf >= '0' && *li->lex_buf <= '9')
486         p->u.known = odr_intdup (o, atoi(li->lex_buf));
487     else
488     {
489         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
490         return NULL;
491     }
492     return p;
493 }
494
495 static Z_Complex *rpn_complex (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
496                                int num_attr, int max_attr, 
497                                int *attr_list, char **attr_clist,
498                                oid_value *attr_set)
499 {
500     Z_Complex *zc;
501     Z_Operator *zo;
502
503     zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
504     zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
505     zc->roperator = zo;
506     switch (li->query_look)
507     {
508     case 'a':
509         zo->which = Z_Operator_and;
510         zo->u.op_and = odr_nullval();
511         break;
512     case 'o':
513         zo->which = Z_Operator_or;
514         zo->u.op_or = odr_nullval();
515         break;
516     case 'n':
517         zo->which = Z_Operator_and_not;
518         zo->u.and_not = odr_nullval();
519         break;
520     case 'p':
521         zo->which = Z_Operator_prox;
522         zo->u.prox = rpn_proximity (li, o);
523         if (!zo->u.prox)
524             return NULL;
525         break;
526     default:
527         /* we're only called if one of the above types are seens so
528            this shouldn't happen */
529         li->error = YAZ_PQF_ERROR_INTERNAL;
530         return NULL;
531     }
532     lex (li);
533     if (!(zc->s1 =
534           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
535                          attr_clist, attr_set)))
536         return NULL;
537     if (!(zc->s2 =
538           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
539                          attr_clist, attr_set)))
540         return NULL;
541     return zc;
542 }
543
544 static void rpn_term_type (struct yaz_pqf_parser *li, ODR o)
545 {
546     if (!li->query_look)
547         return ;
548     if (compare_term (li, "general", 0))
549         li->term_type = Z_Term_general;
550     else if (compare_term (li, "numeric", 0))
551         li->term_type = Z_Term_numeric;
552     else if (compare_term (li, "string", 0))
553         li->term_type = Z_Term_characterString;
554     else if (compare_term (li, "oid", 0))
555         li->term_type = Z_Term_oid;
556     else if (compare_term (li, "datetime", 0))
557         li->term_type = Z_Term_dateTime;
558     else if (compare_term (li, "null", 0))
559         li->term_type = Z_Term_null;
560     else if (compare_term(li, "range", 0))
561     {
562         /* prepare for external: range search .. */
563         li->term_type = Z_Term_external;
564         li->external_type = VAL_MULTISRCH2;
565     }
566     lex (li);
567 }
568                            
569 static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
570                                       oid_proto proto, 
571                                       int num_attr, int max_attr, 
572                                       int *attr_list,
573                                       char **attr_clist,
574                                       oid_value *attr_set)
575 {
576     Z_RPNStructure *sz;
577
578     sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
579     switch (li->query_look)
580     {
581     case 'a':
582     case 'o':
583     case 'n':
584     case 'p':
585         sz->which = Z_RPNStructure_complex;
586         if (!(sz->u.complex =
587               rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
588                            attr_clist, attr_set)))
589             return NULL;
590         break;
591     case 't':
592     case 's':
593         sz->which = Z_RPNStructure_simple;
594         if (!(sz->u.simple =
595               rpn_simple (li, o, proto, num_attr, attr_list,
596                           attr_clist, attr_set)))
597             return NULL;
598         break;
599     case 'l':
600         lex (li);
601         if (!li->query_look)
602         {
603             li->error = YAZ_PQF_ERROR_MISSING;
604             return 0;
605         }
606         if (num_attr >= max_attr)
607         {
608             li->error = YAZ_PQF_ERROR_TOOMANY;
609             return 0;
610         }
611         if (!p_query_parse_attr(li, o, num_attr, attr_list,
612                                 attr_clist, attr_set))
613             return 0;
614         num_attr++;
615         lex (li);
616         return
617             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
618                            attr_clist,  attr_set);
619     case 'y':
620         lex (li);
621         rpn_term_type (li, o);
622         return
623             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
624                            attr_clist, attr_set);
625     case 0:                /* operator/operand expected! */
626         li->error = YAZ_PQF_ERROR_MISSING;
627         return 0;
628     }
629     return sz;
630 }
631
632 Z_RPNQuery *p_query_rpn_mk (ODR o, struct yaz_pqf_parser *li, oid_proto proto,
633                             const char *qbuf)
634 {
635     Z_RPNQuery *zq;
636     int attr_array[1024];
637     char *attr_clist[512];
638     oid_value attr_set[512];
639     oid_value topSet = VAL_NONE;
640
641     zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
642     lex (li);
643     if (li->query_look == 'r')
644     {
645         lex (li);
646         topSet = query_oid_getvalbyname (li);
647         if (topSet == VAL_NONE)
648         {
649             li->error = YAZ_PQF_ERROR_ATTSET;
650             return NULL;
651         }
652
653         lex (li);
654     }
655     if (topSet == VAL_NONE)
656         topSet = p_query_dfset;
657     if (topSet == VAL_NONE)
658         topSet = VAL_BIB1;
659
660     zq->attributeSetId = yaz_oidval_to_z3950oid(o, CLASS_ATTSET, topSet);
661
662     if (!zq->attributeSetId)
663     {
664         li->error = YAZ_PQF_ERROR_ATTSET;
665         return 0;
666     }
667
668     if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
669                                             attr_array, attr_clist, attr_set)))
670         return 0;
671     if (li->query_look)
672     {
673         li->error = YAZ_PQF_ERROR_EXTRA;
674         return 0;
675     }
676     return zq;
677 }
678
679 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf)
680 {
681     struct yaz_pqf_parser li;
682
683     li.error = 0;
684     li.left_sep = "{\"";
685     li.right_sep = "}\"";
686     li.escape_char = '@';
687     li.term_type = Z_Term_general;
688     li.query_buf = li.query_ptr = qbuf;
689     li.lex_buf = 0;
690     return p_query_rpn_mk (o, &li, proto, qbuf);
691 }
692
693
694 Z_AttributesPlusTerm *p_query_scan_mk (struct yaz_pqf_parser *li,
695                                        ODR o, oid_proto proto,
696                                        Odr_oid **attributeSetP,
697                                        const char *qbuf)
698 {
699     int attr_list[1024];
700     char *attr_clist[512];
701     oid_value attr_set[512];
702     int num_attr = 0;
703     int max_attr = 512;
704     oid_value topSet = VAL_NONE;
705     Z_AttributesPlusTerm *apt;
706
707     lex (li);
708     if (li->query_look == 'r')
709     {
710         lex (li);
711         topSet = query_oid_getvalbyname (li);
712
713         lex (li);
714     }
715     if (topSet == VAL_NONE)
716         topSet = p_query_dfset;
717     if (topSet == VAL_NONE)
718         topSet = VAL_BIB1;
719
720     *attributeSetP = yaz_oidval_to_z3950oid (o, CLASS_ATTSET, topSet);
721
722     while (1)
723     {
724         if (li->query_look == 'l')
725         {
726             lex (li);
727             if (!li->query_look)
728             {
729                 li->error = YAZ_PQF_ERROR_MISSING;
730                 return 0;
731             }
732             if (num_attr >= max_attr)
733             {
734                 li->error = YAZ_PQF_ERROR_TOOMANY;
735                 return 0;
736             }
737             if (!p_query_parse_attr(li, o, num_attr, attr_list,
738                                     attr_clist, attr_set))
739                 return 0;
740             num_attr++;
741             lex (li);
742         }
743         else if (li->query_look == 'y')
744         {
745             lex (li);
746             rpn_term_type (li, o);
747         }
748         else
749             break;
750     }
751     if (!li->query_look)
752     {
753         li->error = YAZ_PQF_ERROR_MISSING;
754         return 0;
755     }
756     apt = rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
757
758     lex (li);
759
760     if (li->query_look != 0)
761     {
762         li->error = YAZ_PQF_ERROR_EXTRA;
763         return 0;
764     }
765     return apt;
766 }
767
768 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
769                                     Odr_oid **attributeSetP,
770                                     const char *qbuf)
771 {
772     struct yaz_pqf_parser li;
773
774     li.error = 0;
775     li.left_sep = "{\"";
776     li.right_sep = "}\"";
777     li.escape_char = '@';
778     li.term_type = Z_Term_general;
779     li.query_buf = li.query_ptr = qbuf;
780     li.lex_buf = 0;
781
782     return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
783 }
784
785 int p_query_attset (const char *arg)
786 {
787     p_query_dfset = oid_getvalbyname (arg);
788     return (p_query_dfset == VAL_NONE) ? -1 : 0;
789 }
790
791 YAZ_PQF_Parser yaz_pqf_create (void)
792 {
793     YAZ_PQF_Parser p = (YAZ_PQF_Parser) xmalloc (sizeof(*p));
794
795     p->error = 0;
796     p->left_sep = "{\"";
797     p->right_sep = "}\"";
798     p->escape_char = '@';
799     p->term_type = Z_Term_general;
800
801     return p;
802 }
803
804 void yaz_pqf_destroy (YAZ_PQF_Parser p)
805 {
806     xfree (p);
807 }
808
809 Z_RPNQuery *yaz_pqf_parse (YAZ_PQF_Parser p, ODR o, const char *qbuf)
810 {
811     if (!p)
812         return 0;
813     p->query_buf = p->query_ptr = qbuf;
814     p->lex_buf = 0;
815     return p_query_rpn_mk (o, p, PROTO_Z3950, qbuf);
816 }
817
818 Z_AttributesPlusTerm *yaz_pqf_scan (YAZ_PQF_Parser p, ODR o,
819                                     Odr_oid **attributeSetP,
820                                     const char *qbuf)
821 {
822     if (!p)
823         return 0;
824     p->query_buf = p->query_ptr = qbuf;
825     p->lex_buf = 0;
826     return p_query_scan_mk (p, o, PROTO_Z3950, attributeSetP, qbuf);
827 }
828
829 int yaz_pqf_error (YAZ_PQF_Parser p, const char **msg, size_t *off)
830 {
831     switch (p->error)
832     {
833     case YAZ_PQF_ERROR_NONE:
834         *msg = "no error"; break;
835     case YAZ_PQF_ERROR_EXTRA:
836         *msg = "extra token"; break;
837     case YAZ_PQF_ERROR_MISSING:
838         *msg = "missing token"; break;
839     case YAZ_PQF_ERROR_ATTSET:
840         *msg = "unknown attribute set"; break;
841     case YAZ_PQF_ERROR_TOOMANY:
842         *msg = "too many attributes"; break;
843     case YAZ_PQF_ERROR_BADATTR:
844         *msg = "bad attribute specification"; break;
845     case YAZ_PQF_ERROR_INTERNAL:
846         *msg = "internal error"; break;
847     case YAZ_PQF_ERROR_PROXIMITY:
848         *msg = "proximity error"; break;
849     case YAZ_PQF_ERROR_BAD_INTEGER:
850         *msg = "bad integer"; break;
851     default:
852         *msg = "unknown error"; break;
853     }
854     *off = p->query_ptr - p->query_buf;
855     return p->error;
856 }
857 /*
858  * Local variables:
859  * c-basic-offset: 4
860  * indent-tabs-mode: nil
861  * End:
862  * vim: shiftwidth=4 tabstop=8 expandtab
863  */
864