Add Zthes tag-set -- where was it?!
[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.18 2002-09-24 08:05:42 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 = (char*) term_octet->buf; 
328                                     /* null terminated above */
329         break;
330     case Z_Term_numeric:
331         term->which = Z_Term_numeric;
332         term->u.numeric = odr_intdup (o, atoi((char*) (term_octet->buf)));
333         break;
334     case Z_Term_null:
335         term->which = Z_Term_null;
336         term->u.null = odr_nullval();
337         break;
338     default:
339         term->which = Z_Term_null;
340         term->u.null = odr_nullval();
341         break;
342     }
343     return zapt;
344 }
345
346 static Z_Operand *rpn_simple (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
347                               int num_attr, int *attr_list, char **attr_clist,
348                               oid_value *attr_set)
349 {
350     Z_Operand *zo;
351
352     zo = (Z_Operand *)odr_malloc (o, sizeof(*zo));
353     switch (li->query_look)
354     {
355     case 't':
356         zo->which = Z_Operand_APT;
357         if (!(zo->u.attributesPlusTerm =
358               rpn_term (li, o, proto, num_attr, attr_list, attr_clist,
359                         attr_set)))
360             return 0;
361         lex (li);
362         break;
363     case 's':
364         lex (li);
365         if (!li->query_look)
366         {
367             li->error = YAZ_PQF_ERROR_MISSING;
368             return 0;
369         }
370         zo->which = Z_Operand_resultSetId;
371         zo->u.resultSetId = (char *)odr_malloc (o, li->lex_len+1);
372         memcpy (zo->u.resultSetId, li->lex_buf, li->lex_len);
373         zo->u.resultSetId[li->lex_len] = '\0';
374         lex (li);
375         break;
376     default:
377         /* we're only called if one of the above types are seens so
378            this shouldn't happen */
379         li->error = YAZ_PQF_ERROR_INTERNAL;
380         return 0;
381     }
382     return zo;
383 }
384
385 static Z_ProximityOperator *rpn_proximity (struct yaz_pqf_parser *li, ODR o)
386 {
387     Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc (o, sizeof(*p));
388
389     if (!lex (li))
390     {
391         li->error = YAZ_PQF_ERROR_MISSING;
392         return NULL;
393     }
394     if (*li->lex_buf == '1')
395     {
396         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
397         *p->exclusion = 1;
398     } 
399     else if (*li->lex_buf == '0')
400     {
401         p->exclusion = (int *)odr_malloc (o, sizeof(*p->exclusion));
402         *p->exclusion = 0;
403     }
404     else
405         p->exclusion = NULL;
406
407     if (!lex (li))
408     {
409         li->error = YAZ_PQF_ERROR_MISSING;
410         return NULL;
411     }
412     p->distance = (int *)odr_malloc (o, sizeof(*p->distance));
413     *p->distance = atoi (li->lex_buf);
414
415     if (!lex (li))
416     {
417         li->error = YAZ_PQF_ERROR_MISSING;
418         return NULL;
419     }
420     p->ordered = (int *)odr_malloc (o, sizeof(*p->ordered));
421     *p->ordered = atoi (li->lex_buf);
422     
423     if (!lex (li))
424     {
425         li->error = YAZ_PQF_ERROR_MISSING;
426         return NULL;
427     }
428     p->relationType = (int *)odr_malloc (o, sizeof(*p->relationType));
429     *p->relationType = atoi (li->lex_buf);
430
431     if (!lex (li))
432     {
433         li->error = YAZ_PQF_ERROR_MISSING;
434         return NULL;
435     }
436     if (*li->lex_buf == 'k')
437         p->which = 0;
438     else if (*li->lex_buf == 'p')
439         p->which = 1;
440     else
441         p->which = atoi (li->lex_buf);
442
443     if (!lex (li))
444     {
445         li->error = YAZ_PQF_ERROR_MISSING;
446         return NULL;
447     }
448     p->which = Z_ProximityOperator_known;
449     p->u.known = (int *)odr_malloc (o, sizeof(*p->u.known));
450     *p->u.known = atoi (li->lex_buf);
451     return p;
452 }
453
454 static Z_Complex *rpn_complex (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
455                                int num_attr, int max_attr, 
456                                int *attr_list, char **attr_clist,
457                                oid_value *attr_set)
458 {
459     Z_Complex *zc;
460     Z_Operator *zo;
461
462     zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
463     zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
464     zc->roperator = zo;
465     switch (li->query_look)
466     {
467     case 'a':
468         zo->which = Z_Operator_and;
469         zo->u.and_not = odr_nullval();
470         break;
471     case 'o':
472         zo->which = Z_Operator_or;
473         zo->u.and_not = odr_nullval();
474         break;
475     case 'n':
476         zo->which = Z_Operator_and_not;
477         zo->u.and_not = odr_nullval();
478         break;
479     case 'p':
480         zo->which = Z_Operator_prox;
481         zo->u.prox = rpn_proximity (li, o);
482         if (!zo->u.prox)
483             return NULL;
484         break;
485     default:
486         /* we're only called if one of the above types are seens so
487            this shouldn't happen */
488         li->error = YAZ_PQF_ERROR_INTERNAL;
489         return NULL;
490     }
491     lex (li);
492     if (!(zc->s1 =
493           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
494                          attr_clist, attr_set)))
495         return NULL;
496     if (!(zc->s2 =
497           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
498                          attr_clist, attr_set)))
499         return NULL;
500     return zc;
501 }
502
503 static void rpn_term_type (struct yaz_pqf_parser *li, ODR o)
504 {
505     if (!li->query_look)
506         return ;
507     if (compare_term (li, "general", 0))
508         li->term_type = Z_Term_general;
509     else if (compare_term (li, "numeric", 0))
510         li->term_type = Z_Term_numeric;
511     else if (compare_term (li, "string", 0))
512         li->term_type = Z_Term_characterString;
513     else if (compare_term (li, "oid", 0))
514         li->term_type = Z_Term_oid;
515     else if (compare_term (li, "datetime", 0))
516         li->term_type = Z_Term_dateTime;
517     else if (compare_term (li, "null", 0))
518         li->term_type = Z_Term_null;
519     lex (li);
520 }
521                            
522 static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
523                                       oid_proto proto, 
524                                       int num_attr, int max_attr, 
525                                       int *attr_list,
526                                       char **attr_clist,
527                                       oid_value *attr_set)
528 {
529     Z_RPNStructure *sz;
530
531     sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
532     switch (li->query_look)
533     {
534     case 'a':
535     case 'o':
536     case 'n':
537     case 'p':
538         sz->which = Z_RPNStructure_complex;
539         if (!(sz->u.complex =
540               rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
541                            attr_clist, attr_set)))
542             return NULL;
543         break;
544     case 't':
545     case 's':
546         sz->which = Z_RPNStructure_simple;
547         if (!(sz->u.simple =
548               rpn_simple (li, o, proto, num_attr, attr_list,
549                           attr_clist, attr_set)))
550             return NULL;
551         break;
552     case 'l':
553         lex (li);
554         if (!li->query_look)
555         {
556             li->error = YAZ_PQF_ERROR_MISSING;
557             return 0;
558         }
559         if (num_attr >= max_attr)
560         {
561             li->error = YAZ_PQF_ERROR_TOOMANY;
562             return 0;
563         }
564         if (!p_query_parse_attr(li, o, num_attr, attr_list,
565                                 attr_clist, attr_set))
566             return 0;
567         num_attr++;
568         lex (li);
569         return
570             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
571                            attr_clist,  attr_set);
572     case 'y':
573         lex (li);
574         rpn_term_type (li, o);
575         return
576             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
577                            attr_clist, attr_set);
578     case 0:                /* operator/operand expected! */
579         li->error = YAZ_PQF_ERROR_MISSING;
580         return 0;
581     }
582     return sz;
583 }
584
585 Z_RPNQuery *p_query_rpn_mk (ODR o, struct yaz_pqf_parser *li, oid_proto proto,
586                             const char *qbuf)
587 {
588     Z_RPNQuery *zq;
589     int attr_array[1024];
590     char *attr_clist[512];
591     oid_value attr_set[512];
592     oid_value topSet = VAL_NONE;
593
594     zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
595     lex (li);
596     if (li->query_look == 'r')
597     {
598         lex (li);
599         topSet = query_oid_getvalbyname (li);
600         if (topSet == VAL_NONE)
601         {
602             li->error = YAZ_PQF_ERROR_ATTSET;
603             return NULL;
604         }
605
606         lex (li);
607     }
608     if (topSet == VAL_NONE)
609         topSet = p_query_dfset;
610     if (topSet == VAL_NONE)
611         topSet = VAL_BIB1;
612
613     zq->attributeSetId = yaz_oidval_to_z3950oid(o, CLASS_ATTSET, topSet);
614
615     if (!zq->attributeSetId)
616     {
617         li->error = YAZ_PQF_ERROR_ATTSET;
618         return 0;
619     }
620
621     if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
622                                             attr_array, attr_clist, attr_set)))
623         return 0;
624     if (li->query_look)
625     {
626         li->error = YAZ_PQF_ERROR_EXTRA;
627         return 0;
628     }
629     return zq;
630 }
631
632 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto,
633                          const char *qbuf)
634 {
635     struct yaz_pqf_parser li;
636
637     li.error = 0;
638     li.left_sep = "{\"";
639     li.right_sep = "}\"";
640     li.escape_char = '@';
641     li.term_type = Z_Term_general;
642     li.query_buf = li.query_ptr = qbuf;
643     li.lex_buf = 0;
644     return p_query_rpn_mk (o, &li, proto, qbuf);
645 }
646
647
648 Z_AttributesPlusTerm *p_query_scan_mk (struct yaz_pqf_parser *li,
649                                        ODR o, oid_proto proto,
650                                        Odr_oid **attributeSetP,
651                                        const char *qbuf)
652 {
653     int attr_list[1024];
654     char *attr_clist[512];
655     oid_value attr_set[512];
656     int num_attr = 0;
657     int max_attr = 512;
658     oid_value topSet = VAL_NONE;
659     Z_AttributesPlusTerm *apt;
660
661     lex (li);
662     if (li->query_look == 'r')
663     {
664         lex (li);
665         topSet = query_oid_getvalbyname (li);
666
667         lex (li);
668     }
669     if (topSet == VAL_NONE)
670         topSet = p_query_dfset;
671     if (topSet == VAL_NONE)
672         topSet = VAL_BIB1;
673
674     *attributeSetP = yaz_oidval_to_z3950oid (o, CLASS_ATTSET, topSet);
675
676     while (1)
677     {
678         if (li->query_look == 'l')
679         {
680             lex (li);
681             if (!li->query_look)
682             {
683                 li->error = YAZ_PQF_ERROR_MISSING;
684                 return 0;
685             }
686             if (num_attr >= max_attr)
687             {
688                 li->error = YAZ_PQF_ERROR_TOOMANY;
689                 return 0;
690             }
691             if (!p_query_parse_attr(li, o, num_attr, attr_list,
692                                     attr_clist, attr_set))
693                 return 0;
694             num_attr++;
695             lex (li);
696         }
697         else if (li->query_look == 'y')
698         {
699             lex (li);
700             rpn_term_type (li, o);
701         }
702         else
703             break;
704     }
705     if (!li->query_look)
706     {
707         li->error = YAZ_PQF_ERROR_MISSING;
708         return 0;
709     }
710     apt = rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
711
712     lex (li);
713
714     if (li->query_look != 0)
715     {
716         li->error = YAZ_PQF_ERROR_EXTRA;
717         return 0;
718     }
719     return apt;
720 }
721
722 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
723                                     Odr_oid **attributeSetP,
724                                     const char *qbuf)
725 {
726     struct yaz_pqf_parser li;
727
728     li.error = 0;
729     li.left_sep = "{\"";
730     li.right_sep = "}\"";
731     li.escape_char = '@';
732     li.term_type = Z_Term_general;
733     li.query_buf = li.query_ptr = qbuf;
734     li.lex_buf = 0;
735
736     return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
737 }
738
739 int p_query_attset (const char *arg)
740 {
741     p_query_dfset = oid_getvalbyname (arg);
742     return (p_query_dfset == VAL_NONE) ? -1 : 0;
743 }
744
745 YAZ_PQF_Parser yaz_pqf_create (void)
746 {
747     YAZ_PQF_Parser p = (YAZ_PQF_Parser) xmalloc (sizeof(*p));
748
749     p->error = 0;
750     p->left_sep = "{\"";
751     p->right_sep = "}\"";
752     p->escape_char = '@';
753     p->term_type = Z_Term_general;
754
755     return p;
756 }
757
758 void yaz_pqf_destroy (YAZ_PQF_Parser p)
759 {
760     xfree (p);
761 }
762
763 Z_RPNQuery *yaz_pqf_parse (YAZ_PQF_Parser p, ODR o, const char *qbuf)
764 {
765     if (!p)
766         return 0;
767     p->query_buf = p->query_ptr = qbuf;
768     p->lex_buf = 0;
769     return p_query_rpn_mk (o, p, PROTO_Z3950, qbuf);
770 }
771
772 Z_AttributesPlusTerm *yaz_pqf_scan (YAZ_PQF_Parser p, ODR o,
773                                     Odr_oid **attributeSetP,
774                                     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_scan_mk (p, o, PROTO_Z3950, attributeSetP, qbuf);
781 }
782
783 int yaz_pqf_error (YAZ_PQF_Parser p, const char **msg, size_t *off)
784 {
785     switch (p->error)
786     {
787     case YAZ_PQF_ERROR_NONE:
788         *msg = "no error"; break;
789     case YAZ_PQF_ERROR_EXTRA:
790         *msg = "extra token"; break;
791     case YAZ_PQF_ERROR_MISSING:
792         *msg = "missing token"; break;
793     case YAZ_PQF_ERROR_ATTSET:
794         *msg = "unknown attribute set"; break;
795     case YAZ_PQF_ERROR_TOOMANY:
796         *msg = "too many attributes"; break;
797     case YAZ_PQF_ERROR_BADATTR:
798         *msg = "bad attribute specification"; break;
799     case YAZ_PQF_ERROR_INTERNAL:
800         *msg = "internal error"; break;
801     default:
802         *msg = "unknown error"; break;
803     }
804     *off = p->query_ptr - p->query_buf;
805     return p->error;
806 }