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