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