Accept application/soap+xml as content-type for SOAP msg
[yaz-moved-to-github.git] / src / pquery.c
1 /*
2  * Copyright (C) 1995-2005, Index Data ApS
3  * See the file LICENSE for details.
4  *
5  * $Id: pquery.c,v 1.7 2006-02-19 18:34:13 adam Exp $
6  */
7 /**
8  * \file pquery.c
9  * \brief Implements PQF parsing
10  */
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15
16 #include <yaz/proto.h>
17 #include <yaz/oid.h>
18 #include <yaz/pquery.h>
19
20 static oid_value p_query_dfset = VAL_NONE;
21
22 struct yaz_pqf_parser {
23     const char *query_buf;
24     const char *query_ptr;
25     const char *lex_buf;
26     size_t lex_len;
27     int query_look;
28     char *left_sep;
29     char *right_sep;
30     int escape_char;
31     int term_type;
32     int external_type;
33     int error;
34 };
35
36 static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
37                                       oid_proto, 
38                                       int num_attr, int max_attr, 
39                                       int *attr_list, char **attr_clist,
40                                       oid_value *attr_set);
41
42 static enum oid_value query_oid_getvalbyname (struct yaz_pqf_parser *li)
43 {
44     enum oid_value value;
45     char buf[32];
46
47     if (li->lex_len > 31)
48         return VAL_NONE;
49     memcpy (buf, li->lex_buf, li->lex_len);
50     buf[li->lex_len] = '\0';
51     value = oid_getvalbyname (buf);
52     return value;
53 }
54
55 static int compare_term (struct yaz_pqf_parser *li, const char *src,
56                          size_t off)
57 {
58     size_t len=strlen(src);
59     
60     if (li->lex_len == len+off && !memcmp (li->lex_buf+off, src, len-off))
61         return 1;
62     return 0;
63 }
64
65 static int query_token (struct yaz_pqf_parser *li)
66 {
67     int sep_char = ' ';
68     const char *sep_match;
69     const char **qptr = &li->query_ptr;
70
71     while (**qptr == ' ')
72         (*qptr)++;
73     if (**qptr == '\0')
74         return 0;
75     li->lex_len = 0;
76     if ((sep_match = strchr (li->left_sep, **qptr)))
77     {
78         sep_char = li->right_sep[sep_match - li->left_sep];
79         ++(*qptr);
80     }
81     li->lex_buf = *qptr;
82    
83     if (**qptr == li->escape_char && isdigit (((const unsigned char *) *qptr)[1]))
84     {
85         ++(li->lex_len);
86         ++(*qptr);
87         return 'l';
88     }
89     while (**qptr && **qptr != sep_char)
90     {
91         if (**qptr == '\\')
92         {
93             ++(li->lex_len);
94             ++(*qptr);
95         }
96         ++(li->lex_len);
97         ++(*qptr);
98     }
99     if (**qptr)
100         ++(*qptr);
101     if (sep_char == ' ' &&
102         li->lex_len >= 1 && li->lex_buf[0] == li->escape_char)
103     {
104         if (compare_term (li, "and", 1))
105             return 'a';
106         if (compare_term (li, "or", 1))
107             return 'o';
108         if (compare_term (li, "not", 1))
109             return 'n';
110         if (compare_term (li, "attr", 1))
111             return 'l';
112         if (compare_term (li, "set", 1))
113             return 's';
114         if (compare_term (li, "attrset", 1))
115             return 'r';
116         if (compare_term (li, "prox", 1))
117             return 'p';
118         if (compare_term (li, "term", 1))
119             return 'y';
120     }
121     return 't';
122 }
123
124 static int lex (struct yaz_pqf_parser *li)
125 {
126     return li->query_look = query_token (li);
127 }
128
129 static int escape_string(char *out_buf, const char *in, int len)
130 {
131
132     char *out = out_buf;
133     while (--len >= 0)
134         if (*in == '\\' && len > 0)
135         {
136             --len;
137             switch (*++in)
138             {
139             case 't':
140                 *out++ = '\t';
141                 break;
142             case 'n':
143                 *out++ = '\n';
144                 break;
145             case 'r':
146                 *out++ = '\r';
147                 break;
148             case 'f':
149                 *out++ = '\f';
150                 break;
151             case 'x':
152                 if (len > 1)
153                 {
154                     char s[4];
155                     int n = 0;
156                     s[0] = *++in;
157                     s[1] = *++in;
158                     s[2] = '\0';
159                     len = len - 2;
160                     sscanf (s, "%x", &n);
161                     *out++ = n;
162                 }
163                 break;
164             case '0':
165             case '1':
166             case '2':
167             case '3':
168                 if (len > 1)
169                 {
170                     char s[4];
171                     int n = 0;
172                     s[0] = *in;
173                     s[1] = *++in;                   
174                     s[2] = *++in;
175                     s[3] = '\0';
176                     len = len - 2;
177                     sscanf (s, "%o", &n);
178                     *out++ = n;
179                 }
180                 break;
181             default:
182                 *out++ = *in;
183                 break;
184             }
185             in++;
186         }
187         else
188             *out++ = *in++;
189     return out - out_buf;
190 }
191
192 static int p_query_parse_attr(struct yaz_pqf_parser *li, ODR o,
193                               int num_attr, int *attr_list,
194                               char **attr_clist, oid_value *attr_set)
195 {
196     const char *cp;
197     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         p->exclusion = odr_intdup (o, 1);
404     else if (*li->lex_buf == '0')
405         p->exclusion = odr_intdup (o, 0);
406     else
407         p->exclusion = NULL;
408
409     if (!lex (li))
410     {
411         li->error = YAZ_PQF_ERROR_MISSING;
412         return NULL;
413     }
414     p->distance = odr_intdup (o, atoi(li->lex_buf));
415
416     if (!lex (li))
417     {
418         li->error = YAZ_PQF_ERROR_MISSING;
419         return NULL;
420     }
421     p->ordered = odr_intdup (o, atoi (li->lex_buf));
422     
423     if (!lex (li))
424     {
425         li->error = YAZ_PQF_ERROR_MISSING;
426         return NULL;
427     }
428     p->relationType = odr_intdup (o, 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 = Z_ProximityOperator_known;
437     else if (*li->lex_buf == 'p')
438         p->which = Z_ProximityOperator_private;
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->u.known = odr_intdup (o, atoi(li->lex_buf));
448     return p;
449 }
450
451 static Z_Complex *rpn_complex (struct yaz_pqf_parser *li, ODR o, oid_proto proto,
452                                int num_attr, int max_attr, 
453                                int *attr_list, char **attr_clist,
454                                oid_value *attr_set)
455 {
456     Z_Complex *zc;
457     Z_Operator *zo;
458
459     zc = (Z_Complex *)odr_malloc (o, sizeof(*zc));
460     zo = (Z_Operator *)odr_malloc (o, sizeof(*zo));
461     zc->roperator = zo;
462     switch (li->query_look)
463     {
464     case 'a':
465         zo->which = Z_Operator_and;
466         zo->u.op_and = odr_nullval();
467         break;
468     case 'o':
469         zo->which = Z_Operator_or;
470         zo->u.op_or = odr_nullval();
471         break;
472     case 'n':
473         zo->which = Z_Operator_and_not;
474         zo->u.and_not = odr_nullval();
475         break;
476     case 'p':
477         zo->which = Z_Operator_prox;
478         zo->u.prox = rpn_proximity (li, o);
479         if (!zo->u.prox)
480             return NULL;
481         break;
482     default:
483         /* we're only called if one of the above types are seens so
484            this shouldn't happen */
485         li->error = YAZ_PQF_ERROR_INTERNAL;
486         return NULL;
487     }
488     lex (li);
489     if (!(zc->s1 =
490           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
491                          attr_clist, attr_set)))
492         return NULL;
493     if (!(zc->s2 =
494           rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
495                          attr_clist, attr_set)))
496         return NULL;
497     return zc;
498 }
499
500 static void rpn_term_type (struct yaz_pqf_parser *li, ODR o)
501 {
502     if (!li->query_look)
503         return ;
504     if (compare_term (li, "general", 0))
505         li->term_type = Z_Term_general;
506     else if (compare_term (li, "numeric", 0))
507         li->term_type = Z_Term_numeric;
508     else if (compare_term (li, "string", 0))
509         li->term_type = Z_Term_characterString;
510     else if (compare_term (li, "oid", 0))
511         li->term_type = Z_Term_oid;
512     else if (compare_term (li, "datetime", 0))
513         li->term_type = Z_Term_dateTime;
514     else if (compare_term (li, "null", 0))
515         li->term_type = Z_Term_null;
516     else if (compare_term(li, "range", 0))
517     {
518         /* prepare for external: range search .. */
519         li->term_type = Z_Term_external;
520         li->external_type = VAL_MULTISRCH2;
521     }
522     lex (li);
523 }
524                            
525 static Z_RPNStructure *rpn_structure (struct yaz_pqf_parser *li, ODR o,
526                                       oid_proto proto, 
527                                       int num_attr, int max_attr, 
528                                       int *attr_list,
529                                       char **attr_clist,
530                                       oid_value *attr_set)
531 {
532     Z_RPNStructure *sz;
533
534     sz = (Z_RPNStructure *)odr_malloc (o, sizeof(*sz));
535     switch (li->query_look)
536     {
537     case 'a':
538     case 'o':
539     case 'n':
540     case 'p':
541         sz->which = Z_RPNStructure_complex;
542         if (!(sz->u.complex =
543               rpn_complex (li, o, proto, num_attr, max_attr, attr_list,
544                            attr_clist, attr_set)))
545             return NULL;
546         break;
547     case 't':
548     case 's':
549         sz->which = Z_RPNStructure_simple;
550         if (!(sz->u.simple =
551               rpn_simple (li, o, proto, num_attr, attr_list,
552                           attr_clist, attr_set)))
553             return NULL;
554         break;
555     case 'l':
556         lex (li);
557         if (!li->query_look)
558         {
559             li->error = YAZ_PQF_ERROR_MISSING;
560             return 0;
561         }
562         if (num_attr >= max_attr)
563         {
564             li->error = YAZ_PQF_ERROR_TOOMANY;
565             return 0;
566         }
567         if (!p_query_parse_attr(li, o, num_attr, attr_list,
568                                 attr_clist, attr_set))
569             return 0;
570         num_attr++;
571         lex (li);
572         return
573             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
574                            attr_clist,  attr_set);
575     case 'y':
576         lex (li);
577         rpn_term_type (li, o);
578         return
579             rpn_structure (li, o, proto, num_attr, max_attr, attr_list,
580                            attr_clist, attr_set);
581     case 0:                /* operator/operand expected! */
582         li->error = YAZ_PQF_ERROR_MISSING;
583         return 0;
584     }
585     return sz;
586 }
587
588 Z_RPNQuery *p_query_rpn_mk (ODR o, struct yaz_pqf_parser *li, oid_proto proto,
589                             const char *qbuf)
590 {
591     Z_RPNQuery *zq;
592     int attr_array[1024];
593     char *attr_clist[512];
594     oid_value attr_set[512];
595     oid_value topSet = VAL_NONE;
596
597     zq = (Z_RPNQuery *)odr_malloc (o, sizeof(*zq));
598     lex (li);
599     if (li->query_look == 'r')
600     {
601         lex (li);
602         topSet = query_oid_getvalbyname (li);
603         if (topSet == VAL_NONE)
604         {
605             li->error = YAZ_PQF_ERROR_ATTSET;
606             return NULL;
607         }
608
609         lex (li);
610     }
611     if (topSet == VAL_NONE)
612         topSet = p_query_dfset;
613     if (topSet == VAL_NONE)
614         topSet = VAL_BIB1;
615
616     zq->attributeSetId = yaz_oidval_to_z3950oid(o, CLASS_ATTSET, topSet);
617
618     if (!zq->attributeSetId)
619     {
620         li->error = YAZ_PQF_ERROR_ATTSET;
621         return 0;
622     }
623
624     if (!(zq->RPNStructure = rpn_structure (li, o, proto, 0, 512,
625                                             attr_array, attr_clist, attr_set)))
626         return 0;
627     if (li->query_look)
628     {
629         li->error = YAZ_PQF_ERROR_EXTRA;
630         return 0;
631     }
632     return zq;
633 }
634
635 Z_RPNQuery *p_query_rpn (ODR o, oid_proto proto, const char *qbuf)
636 {
637     struct yaz_pqf_parser li;
638
639     li.error = 0;
640     li.left_sep = "{\"";
641     li.right_sep = "}\"";
642     li.escape_char = '@';
643     li.term_type = Z_Term_general;
644     li.query_buf = li.query_ptr = qbuf;
645     li.lex_buf = 0;
646     return p_query_rpn_mk (o, &li, proto, qbuf);
647 }
648
649
650 Z_AttributesPlusTerm *p_query_scan_mk (struct yaz_pqf_parser *li,
651                                        ODR o, oid_proto proto,
652                                        Odr_oid **attributeSetP,
653                                        const char *qbuf)
654 {
655     int attr_list[1024];
656     char *attr_clist[512];
657     oid_value attr_set[512];
658     int num_attr = 0;
659     int max_attr = 512;
660     oid_value topSet = VAL_NONE;
661     Z_AttributesPlusTerm *apt;
662
663     lex (li);
664     if (li->query_look == 'r')
665     {
666         lex (li);
667         topSet = query_oid_getvalbyname (li);
668
669         lex (li);
670     }
671     if (topSet == VAL_NONE)
672         topSet = p_query_dfset;
673     if (topSet == VAL_NONE)
674         topSet = VAL_BIB1;
675
676     *attributeSetP = yaz_oidval_to_z3950oid (o, CLASS_ATTSET, topSet);
677
678     while (1)
679     {
680         if (li->query_look == 'l')
681         {
682             lex (li);
683             if (!li->query_look)
684             {
685                 li->error = YAZ_PQF_ERROR_MISSING;
686                 return 0;
687             }
688             if (num_attr >= max_attr)
689             {
690                 li->error = YAZ_PQF_ERROR_TOOMANY;
691                 return 0;
692             }
693             if (!p_query_parse_attr(li, o, num_attr, attr_list,
694                                     attr_clist, attr_set))
695                 return 0;
696             num_attr++;
697             lex (li);
698         }
699         else if (li->query_look == 'y')
700         {
701             lex (li);
702             rpn_term_type (li, o);
703         }
704         else
705             break;
706     }
707     if (!li->query_look)
708     {
709         li->error = YAZ_PQF_ERROR_MISSING;
710         return 0;
711     }
712     apt = rpn_term (li, o, proto, num_attr, attr_list, attr_clist, attr_set);
713
714     lex (li);
715
716     if (li->query_look != 0)
717     {
718         li->error = YAZ_PQF_ERROR_EXTRA;
719         return 0;
720     }
721     return apt;
722 }
723
724 Z_AttributesPlusTerm *p_query_scan (ODR o, oid_proto proto,
725                                     Odr_oid **attributeSetP,
726                                     const char *qbuf)
727 {
728     struct yaz_pqf_parser li;
729
730     li.error = 0;
731     li.left_sep = "{\"";
732     li.right_sep = "}\"";
733     li.escape_char = '@';
734     li.term_type = Z_Term_general;
735     li.query_buf = li.query_ptr = qbuf;
736     li.lex_buf = 0;
737
738     return p_query_scan_mk (&li, o, proto, attributeSetP, qbuf);
739 }
740
741 int p_query_attset (const char *arg)
742 {
743     p_query_dfset = oid_getvalbyname (arg);
744     return (p_query_dfset == VAL_NONE) ? -1 : 0;
745 }
746
747 YAZ_PQF_Parser yaz_pqf_create (void)
748 {
749     YAZ_PQF_Parser p = (YAZ_PQF_Parser) xmalloc (sizeof(*p));
750
751     p->error = 0;
752     p->left_sep = "{\"";
753     p->right_sep = "}\"";
754     p->escape_char = '@';
755     p->term_type = Z_Term_general;
756
757     return p;
758 }
759
760 void yaz_pqf_destroy (YAZ_PQF_Parser p)
761 {
762     xfree (p);
763 }
764
765 Z_RPNQuery *yaz_pqf_parse (YAZ_PQF_Parser p, ODR o, const char *qbuf)
766 {
767     if (!p)
768         return 0;
769     p->query_buf = p->query_ptr = qbuf;
770     p->lex_buf = 0;
771     return p_query_rpn_mk (o, p, PROTO_Z3950, qbuf);
772 }
773
774 Z_AttributesPlusTerm *yaz_pqf_scan (YAZ_PQF_Parser p, ODR o,
775                                     Odr_oid **attributeSetP,
776                                     const char *qbuf)
777 {
778     if (!p)
779         return 0;
780     p->query_buf = p->query_ptr = qbuf;
781     p->lex_buf = 0;
782     return p_query_scan_mk (p, o, PROTO_Z3950, attributeSetP, qbuf);
783 }
784
785 int yaz_pqf_error (YAZ_PQF_Parser p, const char **msg, size_t *off)
786 {
787     switch (p->error)
788     {
789     case YAZ_PQF_ERROR_NONE:
790         *msg = "no error"; break;
791     case YAZ_PQF_ERROR_EXTRA:
792         *msg = "extra token"; break;
793     case YAZ_PQF_ERROR_MISSING:
794         *msg = "missing token"; break;
795     case YAZ_PQF_ERROR_ATTSET:
796         *msg = "unknown attribute set"; break;
797     case YAZ_PQF_ERROR_TOOMANY:
798         *msg = "too many attributes"; break;
799     case YAZ_PQF_ERROR_BADATTR:
800         *msg = "bad attribute specification"; break;
801     case YAZ_PQF_ERROR_INTERNAL:
802         *msg = "internal error"; break;
803     default:
804         *msg = "unknown error"; break;
805     }
806     *off = p->query_ptr - p->query_buf;
807     return p->error;
808 }
809 /*
810  * Local variables:
811  * c-basic-offset: 4
812  * indent-tabs-mode: nil
813  * End:
814  * vim: shiftwidth=4 tabstop=8 expandtab
815  */
816