Doxyfile file description. Indentation. No change of code.
[yaz-moved-to-github.git] / src / pquery.c
1 /*
2  * Copyright (c) 1995-2004, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: pquery.c,v 1.2 2004-10-15 00:19:00 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 ((*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     if (!(cp = strchr (li->lex_buf, '=')) ||
198         (size_t) (cp-li->lex_buf) > li->lex_len)
199     {
200         attr_set[num_attr] = query_oid_getvalbyname (li);
201         if (attr_set[num_attr] == VAL_NONE)
202         {
203             li->error = YAZ_PQF_ERROR_ATTSET;
204             return 0;
205         }
206         if (!lex (li))
207         {
208             li->error = YAZ_PQF_ERROR_MISSING;
209             return 0;
210         }
211         if (!(cp = strchr (li->lex_buf, '=')))
212         {
213             li->error = YAZ_PQF_ERROR_BADATTR;
214             return 0;
215         }
216     }
217     else 
218     {
219         if (num_attr > 0)
220             attr_set[num_attr] = attr_set[num_attr-1];
221         else
222             attr_set[num_attr] = VAL_NONE;
223     }
224     attr_list[2*num_attr] = atoi(li->lex_buf);
225         cp++;
226     if (*cp >= '0' && *cp <= '9')
227     {
228         attr_list[2*num_attr+1] = atoi (cp);
229         attr_clist[num_attr] = 0;
230     }
231     else
232     {
233         int len = li->lex_len - (cp - li->lex_buf);
234         attr_list[2*num_attr+1] = 0;
235         attr_clist[num_attr] = (char *) odr_malloc (o, len+1);
236         len = escape_string(attr_clist[num_attr], cp, len);
237         attr_clist[num_attr][len] = '\0';
238     }
239     return 1;
240 }
241
242 static Z_AttributesPlusTerm *rpn_term (struct yaz_pqf_parser *li, ODR o,
243                                        oid_proto proto, 
244                                        int num_attr, int *attr_list,
245                                        char **attr_clist, oid_value *attr_set)
246 {
247     Z_AttributesPlusTerm *zapt;
248     Odr_oct *term_octet;
249     Z_Term *term;
250     Z_AttributeElement **elements;
251
252     zapt = (Z_AttributesPlusTerm *)odr_malloc (o, sizeof(*zapt));
253     term_octet = (Odr_oct *)odr_malloc (o, sizeof(*term_octet));
254     term = (Z_Term *)odr_malloc (o, sizeof(*term));
255
256     if (!num_attr)
257         elements = (Z_AttributeElement**)odr_nullval();
258     else
259     {
260         int i, k = 0;
261         int *attr_tmp;
262
263         elements = (Z_AttributeElement**)
264             odr_malloc (o, num_attr * sizeof(*elements));
265
266         attr_tmp = (int *)odr_malloc (o, num_attr * 2 * sizeof(int));
267         memcpy (attr_tmp, attr_list, num_attr * 2 * sizeof(int));
268         for (i = num_attr; --i >= 0; )
269         {
270             int j;
271             for (j = i+1; j<num_attr; j++)
272                 if (attr_tmp[2*j] == attr_tmp[2*i])
273                     break;
274             if (j < num_attr)
275                 continue;
276             elements[k] =
277                 (Z_AttributeElement*)odr_malloc (o,sizeof(**elements));
278             elements[k]->attributeType = &attr_tmp[2*i];
279             elements[k]->attributeSet =
280                 yaz_oidval_to_z3950oid(o, CLASS_ATTSET, attr_set[i]);
281
282             if (attr_clist[i])
283             {
284                 elements[k]->which = Z_AttributeValue_complex;
285                 elements[k]->value.complex = (Z_ComplexAttribute *)
286                     odr_malloc (o, sizeof(Z_ComplexAttribute));
287                 elements[k]->value.complex->num_list = 1;
288                 elements[k]->value.complex->list =
289                     (Z_StringOrNumeric **)
290                     odr_malloc (o, 1 * sizeof(Z_StringOrNumeric *));
291                 elements[k]->value.complex->list[0] =
292                     (Z_StringOrNumeric *)
293                     odr_malloc (o, sizeof(Z_StringOrNumeric));
294                 elements[k]->value.complex->list[0]->which =
295                     Z_StringOrNumeric_string;
296                 elements[k]->value.complex->list[0]->u.string =
297                     attr_clist[i];
298                 elements[k]->value.complex->semanticAction = (int **)
299                     odr_nullval();
300                 elements[k]->value.complex->num_semanticAction = 0;
301             }
302             else
303             {
304                 elements[k]->which = Z_AttributeValue_numeric;
305                 elements[k]->value.numeric = &attr_tmp[2*i+1];
306             }
307             k++;
308         }
309         num_attr = k;
310     }
311     zapt->attributes = (Z_AttributeList *)
312         odr_malloc (o, sizeof(*zapt->attributes));
313     zapt->attributes->num_attributes = num_attr;
314     zapt->attributes->attributes = elements;
315
316     zapt->term = term;
317
318     term_octet->buf = (unsigned char *)odr_malloc (o, 1 + li->lex_len);
319     term_octet->size = term_octet->len =
320         escape_string ((char *) (term_octet->buf), li->lex_buf, li->lex_len);
321     term_octet->buf[term_octet->size] = 0;  /* null terminate */
322     
323     switch (li->term_type)
324     {
325     case Z_Term_general:
326         term->which = Z_Term_general;
327         term->u.general = term_octet;
328         break;
329     case Z_Term_characterString:
330         term->which = Z_Term_characterString;
331         term->u.characterString = (char*) term_octet->buf; 
332                                     /* null terminated above */
333         break;
334     case Z_Term_numeric:
335         term->which = Z_Term_numeric;
336         term->u.numeric = odr_intdup (o, atoi((char*) (term_octet->buf)));
337         break;
338     case Z_Term_null:
339         term->which = Z_Term_null;
340         term->u.null = odr_nullval();
341         break;
342     case Z_Term_external:
343         term->which = Z_Term_external;
344         term->u.external = 0;
345         break;
346     default:
347         term->which = Z_Term_null;
348         term->u.null = odr_nullval();
349         break;
350     }
351     return zapt;
352 }
353
354 static Z_Operand *rpn_simple (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
355                               int num_attr, int *attr_list, char **attr_clist,
356                               oid_value *attr_set)
357 {
358     Z_Operand *zo;
359
360     zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
361     switch (li->query_look)
362     {
363     case 't':
364         zo->which = Z_Operand_APT;
365         if (!(zo->u.attributesPlusTerm =
366               rpn_term (li, o, proto, num_attr, attr_list, attr_clist,
367                         attr_set)))
368             return 0;
369         lex (li);
370         break;
371     case 's':
372         lex (li);
373         if (!li->query_look)
374         {
375             li->error = YAZ_PQF_ERROR_MISSING;
376             return 0;
377         }
378         zo->which = Z_Operand_resultSetId;
379         zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
380         memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
381         zo->u.resultSetId[li->lex_len] = '\0';
382         lex (li);
383         break;
384     default:
385         /* we're only called if one of the above types are seens so
386            this shouldn't happen */
387         li->error = YAZ_PQF_ERROR_INTERNAL;
388         return 0;
389     }
390     return zo;
391 }
392
393 static Z_ProximityOperator *rpn_proximity (struct yaz_pqf_parser *li, ODR o)
394 {
395     Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
396
397     if (!lex (li))
398     {
399         li->error = YAZ_PQF_ERROR_MISSING;
400         return NULL;
401     }
402     if (*li->lex_buf == '1')
403     {
404         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
405         *p->exclusion = 1;
406     } 
407     else if (*li->lex_buf == '0')
408     {
409         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
410         *p->exclusion = 0;
411     }
412     else
413         p->exclusion = NULL;
414
415     if (!lex (li))
416     {
417         li->error = YAZ_PQF_ERROR_MISSING;
418         return NULL;
419     }
420     p->distance = (int *)odr_malloc (o, sizeof(*p->distance));
421     *p->distance = atoi (li->lex_buf);
422
423     if (!lex (li))
424     {
425         li->error = YAZ_PQF_ERROR_MISSING;
426         return NULL;
427     }
428     p->ordered = (int *)odr_malloc (o, sizeof(*p->ordered));
429     *p->ordered = atoi (li->lex_buf);
430     
431     if (!lex (li))
432     {
433         li->error = YAZ_PQF_ERROR_MISSING;
434         return NULL;
435     }
436     p->relationType = (int *)odr_malloc (o, sizeof(*p->relationType));
437     *p->relationType = atoi (li->lex_buf);
438
439     if (!lex (li))
440     {
441         li->error = YAZ_PQF_ERROR_MISSING;
442         return NULL;
443     }
444     if (*li->lex_buf == 'k')
445         p->which = 0;
446     else if (*li->lex_buf == 'p')
447         p->which = 1;
448     else
449         p->which = atoi (li->lex_buf);
450
451     if (!lex (li))
452     {
453         li->error = YAZ_PQF_ERROR_MISSING;
454         return NULL;
455     }
456     p->which = Z_ProximityOperator_known;
457     p->u.known = (int *)odr_malloc (o, sizeof(*p->u.known));
458     *p->u.known = atoi (li->lex_buf);
459     return p;
460 }
461
462 static Z_Complex *rpn_complex (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
463                                int num_attr, int max_attr, 
464                                int *attr_list, char **attr_clist,
465                                oid_value *attr_set)
466 {
467     Z_Complex *zc;
468     Z_Operator *zo;
469
470     zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
471     zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
472     zc->roperator = zo;
473     switch (li->query_look)
474     {
475     case 'a':
476         zo->which = Z_Operator_and;
477         zo->u.and_not = odr_nullval();
478         break;
479     case 'o':
480         zo->which = Z_Operator_or;
481         zo->u.and_not = odr_nullval();
482         break;
483     case 'n':
484         zo->which = Z_Operator_and_not;
485         zo->u.and_not = odr_nullval();
486         break;
487     case 'p':
488         zo->which = Z_Operator_prox;
489         zo->u.prox = rpn_proximity (li, o);
490         if (!zo->u.prox)
491             return NULL;
492         break;
493     default:
494         /* we're only called if one of the above types are seens so
495            this shouldn't happen */
496         li->error = YAZ_PQF_ERROR_INTERNAL;
497         return NULL;
498     }
499     lex (li);
500     if (!(zc->s1 =
501           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
502                          attr_clist, attr_set)))
503         return NULL;
504     if (!(zc->s2 =
505           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
506                          attr_clist, attr_set)))
507         return NULL;
508     return zc;
509 }
510
511 static void rpn_term_type (struct yaz_pqf_parser *li, ODR o)
512 {
513     if (!li->query_look)
514         return ;
515     if (compare_term (li, "general", 0))
516         li->term_type = Z_Term_general;
517     else if (compare_term (li, "numeric", 0))
518         li->term_type = Z_Term_numeric;
519     else if (compare_term (li, "string", 0))
520         li->term_type = Z_Term_characterString;
521     else if (compare_term (li, "oid", 0))
522         li->term_type = Z_Term_oid;
523     else if (compare_term (li, "datetime", 0))
524         li->term_type = Z_Term_dateTime;
525     else if (compare_term (li, "null", 0))
526         li->term_type = Z_Term_null;
527     else if (compare_term(li, "range", 0))
528     {
529         /* prepare for external: range search .. */
530         li->term_type = Z_Term_external;
531         li->external_type = VAL_MULTISRCH2;
532     }
533     lex (li);
534 }
535                            
536 static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
537                                       oid_proto proto, 
538                                       int num_attr, int max_attr, 
539                                       int *attr_list,
540                                       char **attr_clist,
541                                       oid_value *attr_set)
542 {
543     Z_RPNStructure *sz;
544
545     sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
546     switch (li->query_look)
547     {
548     case 'a':
549     case 'o':
550     case 'n':
551     case 'p':
552         sz->which = Z_RPNStructure_complex;
553         if (!(sz->u.complex =
554               rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
555                            attr_clist, attr_set)))
556             return NULL;
557         break;
558     case 't':
559     case 's':
560         sz->which = Z_RPNStructure_simple;
561         if (!(sz->u.simple =
562               rpn_simple (li, o, proto, num_attr, attr_list,
563                           attr_clist, attr_set)))
564             return NULL;
565         break;
566     case 'l':
567         lex (li);
568         if (!li->query_look)
569         {
570             li->error = YAZ_PQF_ERROR_MISSING;
571             return 0;
572         }
573         if (num_attr >= max_attr)
574         {
575             li->error = YAZ_PQF_ERROR_TOOMANY;
576             return 0;
577         }
578         if (!p_query_parse_attr(li, o, num_attr, attr_list,
579                                 attr_clist, attr_set))
580             return 0;
581         num_attr++;
582         lex (li);
583         return
584             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
585                            attr_clist,  attr_set);
586     case 'y':
587         lex (li);
588         rpn_term_type (li, o);
589         return
590             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
591                            attr_clist, attr_set);
592     case 0:                /* operator/operand expected! */
593         li->error = YAZ_PQF_ERROR_MISSING;
594         return 0;
595     }
596     return sz;
597 }
598
599 Z_RPNQuery *p_query_rpn_mk (ODR o, struct yaz_pqf_parser *li, oid_proto proto,
600                             const char *qbuf)
601 {
602     Z_RPNQuery *zq;
603     int attr_array[1024];
604     char *attr_clist[512];
605     oid_value attr_set[512];
606     oid_value topSet = VAL_NONE;
607
608     zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
609     lex (li);
610     if (li->query_look == 'r')
611     {
612         lex (li);
613         topSet = query_oid_getvalbyname (li);
614         if (topSet == VAL_NONE)
615         {
616             li->error = YAZ_PQF_ERROR_ATTSET;
617             return NULL;
618         }
619
620         lex (li);
621     }
622     if (topSet == VAL_NONE)
623         topSet = p_query_dfset;
624     if (topSet == VAL_NONE)
625         topSet = VAL_BIB1;
626
627     zq->attributeSetId = yaz_oidval_to_z3950oid(o, CLASS_ATTSET, topSet);
628
629     if (!zq->attributeSetId)
630     {
631         li->error = YAZ_PQF_ERROR_ATTSET;
632         return 0;
633     }
634
635     if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
636                                             attr_array, attr_clist, attr_set)))
637         return 0;
638     if (li->query_look)
639     {
640         li->error = YAZ_PQF_ERROR_EXTRA;
641         return 0;
642     }
643     return zq;
644 }
645
646 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto,
647                          const char *qbuf)
648 {
649     struct yaz_pqf_parser li;
650
651     li.error = 0;
652     li.left_sep = "{\"";
653     li.right_sep = "}\"";
654     li.escape_char = '@';
655     li.term_type = Z_Term_general;
656     li.query_buf = li.query_ptr = qbuf;
657     li.lex_buf = 0;
658     return p_query_rpn_mk (o, &li, proto, qbuf);
659 }
660
661
662 Z_AttributesPlusTerm *p_query_scan_mk (struct yaz_pqf_parser *li,
663                                        ODR o, oid_proto proto,
664                                        Odr_oid **attributeSetP,
665                                        const char *qbuf)
666 {
667     int attr_list[1024];
668     char *attr_clist[512];
669     oid_value attr_set[512];
670     int num_attr = 0;
671     int max_attr = 512;
672     oid_value topSet = VAL_NONE;
673     Z_AttributesPlusTerm *apt;
674
675     lex (li);
676     if (li->query_look == 'r')
677     {
678         lex (li);
679         topSet = query_oid_getvalbyname (li);
680
681         lex (li);
682     }
683     if (topSet == VAL_NONE)
684         topSet = p_query_dfset;
685     if (topSet == VAL_NONE)
686         topSet = VAL_BIB1;
687
688     *attributeSetP = yaz_oidval_to_z3950oid (o, CLASS_ATTSET, topSet);
689
690     while (1)
691     {
692         if (li->query_look == 'l')
693         {
694             lex (li);
695             if (!li->query_look)
696             {
697                 li->error = YAZ_PQF_ERROR_MISSING;
698                 return 0;
699             }
700             if (num_attr >= max_attr)
701             {
702                 li->error = YAZ_PQF_ERROR_TOOMANY;
703                 return 0;
704             }
705             if (!p_query_parse_attr(li, o, num_attr, attr_list,
706                                     attr_clist, attr_set))
707                 return 0;
708             num_attr++;
709             lex (li);
710         }
711         else if (li->query_look == 'y')
712         {
713             lex (li);
714             rpn_term_type (li, o);
715         }
716         else
717             break;
718     }
719     if (!li->query_look)
720     {
721         li->error = YAZ_PQF_ERROR_MISSING;
722         return 0;
723     }
724     apt = rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
725
726     lex (li);
727
728     if (li->query_look != 0)
729     {
730         li->error = YAZ_PQF_ERROR_EXTRA;
731         return 0;
732     }
733     return apt;
734 }
735
736 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
737                                     Odr_oid **attributeSetP,
738                                     const char *qbuf)
739 {
740     struct yaz_pqf_parser li;
741
742     li.error = 0;
743     li.left_sep = "{\"";
744     li.right_sep = "}\"";
745     li.escape_char = '@';
746     li.term_type = Z_Term_general;
747     li.query_buf = li.query_ptr = qbuf;
748     li.lex_buf = 0;
749
750     return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
751 }
752
753 int p_query_attset (const char *arg)
754 {
755     p_query_dfset = oid_getvalbyname (arg);
756     return (p_query_dfset == VAL_NONE) ? -1 : 0;
757 }
758
759 YAZ_PQF_Parser yaz_pqf_create (void)
760 {
761     YAZ_PQF_Parser p = (YAZ_PQF_Parser) xmalloc (sizeof(*p));
762
763     p->error = 0;
764     p->left_sep = "{\"";
765     p->right_sep = "}\"";
766     p->escape_char = '@';
767     p->term_type = Z_Term_general;
768
769     return p;
770 }
771
772 void yaz_pqf_destroy (YAZ_PQF_Parser p)
773 {
774     xfree (p);
775 }
776
777 Z_RPNQuery *yaz_pqf_parse (YAZ_PQF_Parser p, ODR o, const char *qbuf)
778 {
779     if (!p)
780         return 0;
781     p->query_buf = p->query_ptr = qbuf;
782     p->lex_buf = 0;
783     return p_query_rpn_mk (o, p, PROTO_Z3950, qbuf);
784 }
785
786 Z_AttributesPlusTerm *yaz_pqf_scan (YAZ_PQF_Parser p, ODR o,
787                                     Odr_oid **attributeSetP,
788                                     const char *qbuf)
789 {
790     if (!p)
791         return 0;
792     p->query_buf = p->query_ptr = qbuf;
793     p->lex_buf = 0;
794     return p_query_scan_mk (p, o, PROTO_Z3950, attributeSetP, qbuf);
795 }
796
797 int yaz_pqf_error (YAZ_PQF_Parser p, const char **msg, size_t *off)
798 {
799     switch (p->error)
800     {
801     case YAZ_PQF_ERROR_NONE:
802         *msg = "no error"; break;
803     case YAZ_PQF_ERROR_EXTRA:
804         *msg = "extra token"; break;
805     case YAZ_PQF_ERROR_MISSING:
806         *msg = "missing token"; break;
807     case YAZ_PQF_ERROR_ATTSET:
808         *msg = "unknown attribute set"; break;
809     case YAZ_PQF_ERROR_TOOMANY:
810         *msg = "too many attributes"; break;
811     case YAZ_PQF_ERROR_BADATTR:
812         *msg = "bad attribute specification"; break;
813     case YAZ_PQF_ERROR_INTERNAL:
814         *msg = "internal error"; break;
815     default:
816         *msg = "unknown error"; break;
817     }
818     *off = p->query_ptr - p->query_buf;
819     return p->error;
820 }