Merge branch 'master' of ssh://git.indexdata.com/home/git/pub/yaz
[yaz-moved-to-github.git] / src / pquery.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file pquery.c
7  * \brief Implements PQF parsing
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17
18 #include <yaz/proto.h>
19 #include <yaz/oid_db.h>
20 #include <yaz/pquery.h>
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                                      int num_attr, int max_attr, 
38                                      Odr_int *attr_list, char **attr_clist,
39                                      Odr_oid **attr_set);
40
41 static Odr_oid *query_oid_getvalbyname(struct yaz_pqf_parser *li, ODR o)
42 {
43     char buf[32];
44
45     if (li->lex_len >= sizeof(buf)-1)
46         return 0;
47     memcpy(buf, li->lex_buf, li->lex_len);
48     buf[li->lex_len] = '\0';
49     return yaz_string_to_oid_odr(yaz_oid_std(), CLASS_ATTSET, buf, o);
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(((const unsigned char *) *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 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 int p_query_parse_attr(struct yaz_pqf_parser *li, ODR o,
190                               int num_attr, Odr_int *attr_list,
191                               char **attr_clist, Odr_oid **attr_set)
192 {
193     const char *cp;
194     size_t i;
195
196     if (!(cp = strchr(li->lex_buf, '=')) ||
197         (size_t) (cp-li->lex_buf) > li->lex_len)
198     {
199         attr_set[num_attr] = query_oid_getvalbyname(li, o);
200         if (attr_set[num_attr] == 0)
201         {
202             li->error = YAZ_PQF_ERROR_ATTSET;
203             return 0;
204         }
205         if (!lex(li))
206         {
207             li->error = YAZ_PQF_ERROR_MISSING;
208             return 0;
209         }
210         if (!(cp = strchr(li->lex_buf, '=')))
211         {
212             li->error = YAZ_PQF_ERROR_BADATTR;
213             return 0;
214         }
215     }
216     else 
217     {
218         if (num_attr > 0)
219             attr_set[num_attr] = attr_set[num_attr-1];
220         else
221             attr_set[num_attr] = 0;
222     }
223     if (*li->lex_buf < '0' || *li->lex_buf > '9')
224     {
225         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
226         return 0;
227     }
228     attr_list[2*num_attr] = odr_atoi(li->lex_buf);
229     cp++;
230
231     /* inspect value .. and make it a integer if it appears to be */
232     for (i = cp - li->lex_buf; i < li->lex_len; i++)
233         if (li->lex_buf[i] < '0' || li->lex_buf[i] > '9')
234         {
235             int len = li->lex_len - (cp - li->lex_buf);
236             attr_list[2*num_attr+1] = 0;
237             attr_clist[num_attr] = (char *) odr_malloc(o, len+1);
238             len = escape_string(attr_clist[num_attr], cp, len);
239             attr_clist[num_attr][len] = '\0';
240             return 1;
241         }
242     attr_list[2*num_attr+1] = odr_atoi(cp);
243     attr_clist[num_attr] = 0;
244     return 1;
245 }
246
247 Z_AttributeList *get_attributeList(ODR o,
248         int num_attr, Odr_int *attr_list,
249         char **attr_clist, Odr_oid **attr_set)
250 {
251     int i, k = 0;
252     Odr_int *attr_tmp;
253     Z_AttributeElement **elements;
254     Z_AttributeList *attributes= (Z_AttributeList *) odr_malloc(o, sizeof(*attributes));
255     attributes->num_attributes = num_attr;
256     if (!num_attr) {
257         attributes->attributes = (Z_AttributeElement**)odr_nullval();
258         return attributes;
259     }
260     elements = (Z_AttributeElement**) odr_malloc (o, num_attr * sizeof(*elements));
261
262     attr_tmp = (Odr_int *)odr_malloc(o, num_attr * 2 * sizeof(*attr_tmp));
263     memcpy(attr_tmp, attr_list, num_attr * 2 * sizeof(*attr_tmp));
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 = attr_set[i];
276
277         if (attr_clist[i])
278         {
279             elements[k]->which = Z_AttributeValue_complex;
280             elements[k]->value.complex = (Z_ComplexAttribute *)
281                 odr_malloc(o, sizeof(Z_ComplexAttribute));
282             elements[k]->value.complex->num_list = 1;
283             elements[k]->value.complex->list =
284                 (Z_StringOrNumeric **)
285                 odr_malloc(o, 1 * sizeof(Z_StringOrNumeric *));
286             elements[k]->value.complex->list[0] =
287                 (Z_StringOrNumeric *)
288                 odr_malloc(o, sizeof(Z_StringOrNumeric));
289             elements[k]->value.complex->list[0]->which =
290                 Z_StringOrNumeric_string;
291             elements[k]->value.complex->list[0]->u.string =
292                 attr_clist[i];
293             elements[k]->value.complex->semanticAction = 0;
294             elements[k]->value.complex->num_semanticAction = 0;
295         }
296         else
297         {
298             elements[k]->which = Z_AttributeValue_numeric;
299             elements[k]->value.numeric = &attr_tmp[2*i+1];
300         }
301         k++;
302     }
303     attributes->num_attributes = k;
304     attributes->attributes = elements;
305     return attributes;
306 }
307
308 static Z_AttributesPlusTerm *rpn_term_attributes(struct yaz_pqf_parser *li, ODR o, Z_AttributeList *attributes) {
309     Z_AttributesPlusTerm *zapt;
310     Odr_oct *term_octet;
311     Z_Term *term;
312
313     zapt = (Z_AttributesPlusTerm *)odr_malloc(o, sizeof(*zapt));
314     term = (Z_Term *)odr_malloc(o, sizeof(*term));
315     zapt->term = term;
316     zapt->attributes = attributes;
317
318     term_octet = (Odr_oct *)odr_malloc(o, sizeof(*term_octet));
319     term_octet->buf = (unsigned char *)odr_malloc(o, 1 + li->lex_len);
320     term_octet->size = term_octet->len =
321         escape_string((char *) (term_octet->buf), li->lex_buf, li->lex_len);
322     term_octet->buf[term_octet->size] = 0;  /* null terminate */
323     
324     switch (li->term_type)
325     {
326     case Z_Term_general:
327         term->which = Z_Term_general;
328         term->u.general = term_octet;
329         break;
330     case Z_Term_characterString:
331         term->which = Z_Term_characterString;
332         term->u.characterString = (char*) term_octet->buf; 
333         /* null terminated above */
334         break;
335     case Z_Term_numeric:
336         term->which = Z_Term_numeric;
337         term->u.numeric = odr_intdup(o, odr_atoi((const char*) term_octet->buf));
338         break;
339     case Z_Term_null:
340         term->which = Z_Term_null;
341         term->u.null = odr_nullval();
342         break;
343     case Z_Term_external:
344         term->which = Z_Term_external;
345         term->u.external = 0;
346         break;
347     default:
348         term->which = Z_Term_null;
349         term->u.null = odr_nullval();
350         break;
351     }
352     return zapt;
353
354 }
355
356 static Z_AttributesPlusTerm *rpn_term(struct yaz_pqf_parser *li, ODR o,
357                                       int num_attr, Odr_int *attr_list,
358                                       char **attr_clist, Odr_oid **attr_set)
359 {
360     return rpn_term_attributes(li, o, get_attributeList(o, num_attr, attr_list, attr_clist, attr_set));
361 }
362
363 static Z_Operand *rpn_simple(struct yaz_pqf_parser *li, ODR o,
364                              int num_attr, Odr_int *attr_list,
365                              char **attr_clist,
366                              Odr_oid **attr_set)
367 {
368     Z_Operand *zo;
369
370     zo = (Z_Operand *)odr_malloc(o, sizeof(*zo));
371     switch (li->query_look)
372     {
373     case 't':
374         zo->which = Z_Operand_APT;
375         if (!(zo->u.attributesPlusTerm =
376               rpn_term(li, o, num_attr, attr_list, attr_clist, attr_set)))
377             return 0;
378         lex(li);
379         break;
380     case 's':
381         lex(li);
382         if (!li->query_look)
383         {
384             li->error = YAZ_PQF_ERROR_MISSING;
385             return 0;
386         }
387         zo->which = Z_Operand_resultSetId;
388         zo->u.resultSetId = (char *)odr_malloc(o, li->lex_len+1);
389         memcpy(zo->u.resultSetId, li->lex_buf, li->lex_len);
390         zo->u.resultSetId[li->lex_len] = '\0';
391         lex(li);
392         break;
393     default:
394         /* we're only called if one of the above types are seens so
395            this shouldn't happen */
396         li->error = YAZ_PQF_ERROR_INTERNAL;
397         return 0;
398     }
399     return zo;
400 }
401
402 static Z_ProximityOperator *rpn_proximity(struct yaz_pqf_parser *li, ODR o)
403 {
404     Z_ProximityOperator *p = (Z_ProximityOperator *)odr_malloc(o, sizeof(*p));
405
406     if (!lex(li))
407     {
408         li->error = YAZ_PQF_ERROR_MISSING;
409         return NULL;
410     }
411     if (*li->lex_buf == '1')
412         p->exclusion = odr_booldup(o, 1);
413     else if (*li->lex_buf == '0')
414         p->exclusion = odr_booldup(o, 0);
415     else if (*li->lex_buf == 'v' || *li->lex_buf == 'n')
416         p->exclusion = NULL;
417     else
418     {
419         li->error = YAZ_PQF_ERROR_PROXIMITY;
420         return NULL;
421     }
422
423     if (!lex(li))
424     {
425         li->error = YAZ_PQF_ERROR_MISSING;
426         return NULL;
427     }
428     if (*li->lex_buf >= '0' && *li->lex_buf <= '9')
429         p->distance = odr_intdup(o, odr_atoi(li->lex_buf));
430     else
431     {
432         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
433         return NULL;
434     }
435
436     if (!lex(li))
437     {
438         li->error = YAZ_PQF_ERROR_MISSING;
439         return NULL;
440     }
441     if (*li->lex_buf == '1')
442         p->ordered = odr_booldup(o, 1);
443     else if (*li->lex_buf == '0')
444         p->ordered = odr_booldup(o, 0);
445     else
446     {
447         li->error = YAZ_PQF_ERROR_PROXIMITY;
448         return NULL;
449     }
450     
451     if (!lex (li))
452     {
453         li->error = YAZ_PQF_ERROR_MISSING;
454         return NULL;
455     }
456     if (*li->lex_buf >= '0' && *li->lex_buf <= '9')
457         p->relationType = odr_intdup(o, odr_atoi(li->lex_buf));
458     else
459     {
460         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
461         return NULL;
462     }
463
464     if (!lex(li))
465     {
466         li->error = YAZ_PQF_ERROR_MISSING;
467         return NULL;
468     }
469     if (*li->lex_buf == 'k')
470         p->which = Z_ProximityOperator_known;
471     else if (*li->lex_buf == 'p')
472         p->which = Z_ProximityOperator_private;
473     else
474         p->which = atoi(li->lex_buf);
475
476     if (p->which != Z_ProximityOperator_known
477         && p->which != Z_ProximityOperator_private)
478     {
479         li->error = YAZ_PQF_ERROR_PROXIMITY;
480         return NULL;
481     }
482
483     if (!lex(li))
484     {
485         li->error = YAZ_PQF_ERROR_MISSING;
486         return NULL;
487     }
488     if (*li->lex_buf >= '0' && *li->lex_buf <= '9')
489         p->u.known = odr_intdup(o, odr_atoi(li->lex_buf));
490     else
491     {
492         li->error = YAZ_PQF_ERROR_BAD_INTEGER;
493         return NULL;
494     }
495     return p;
496 }
497
498 static Z_Complex *rpn_complex(struct yaz_pqf_parser *li, ODR o,
499                               int num_attr, int max_attr, 
500                               Odr_int *attr_list, char **attr_clist,
501                               Odr_oid **attr_set)
502 {
503     Z_Complex *zc;
504     Z_Operator *zo;
505
506     zc = (Z_Complex *)odr_malloc(o, sizeof(*zc));
507     zo = (Z_Operator *)odr_malloc(o, sizeof(*zo));
508     zc->roperator = zo;
509     switch (li->query_look)
510     {
511     case 'a':
512         zo->which = Z_Operator_and;
513         zo->u.op_and = odr_nullval();
514         break;
515     case 'o':
516         zo->which = Z_Operator_or;
517         zo->u.op_or = odr_nullval();
518         break;
519     case 'n':
520         zo->which = Z_Operator_and_not;
521         zo->u.and_not = odr_nullval();
522         break;
523     case 'p':
524         zo->which = Z_Operator_prox;
525         zo->u.prox = rpn_proximity(li, o);
526         if (!zo->u.prox)
527             return NULL;
528         break;
529     default:
530         /* we're only called if one of the above types are seens so
531            this shouldn't happen */
532         li->error = YAZ_PQF_ERROR_INTERNAL;
533         return NULL;
534     }
535     lex(li);
536     if (!(zc->s1 =
537           rpn_structure(li, o, num_attr, max_attr, attr_list,
538                         attr_clist, attr_set)))
539         return NULL;
540     if (!(zc->s2 =
541           rpn_structure(li, o, num_attr, max_attr, attr_list,
542                         attr_clist, attr_set)))
543         return NULL;
544     return zc;
545 }
546
547 static void rpn_term_type(struct yaz_pqf_parser *li)
548 {
549     if (!li->query_look)
550         return ;
551     if (compare_term(li, "general", 0))
552         li->term_type = Z_Term_general;
553     else if (compare_term(li, "numeric", 0))
554         li->term_type = Z_Term_numeric;
555     else if (compare_term(li, "string", 0))
556         li->term_type = Z_Term_characterString;
557     else if (compare_term(li, "oid", 0))
558         li->term_type = Z_Term_oid;
559     else if (compare_term(li, "datetime", 0))
560         li->term_type = Z_Term_dateTime;
561     else if (compare_term(li, "null", 0))
562         li->term_type = Z_Term_null;
563 #if 0
564     else if (compare_term(li, "range", 0))
565     {
566         /* prepare for external: range search .. */
567         li->term_type = Z_Term_external;
568         li->external_type = VAL_MULTISRCH2;
569     }
570 #endif
571     lex(li);
572 }
573                            
574 static Z_RPNStructure *rpn_structure(struct yaz_pqf_parser *li, ODR o,
575                                      int num_attr, int max_attr, 
576                                      Odr_int *attr_list,
577                                      char **attr_clist,
578                                      Odr_oid **attr_set)
579 {
580     Z_RPNStructure *sz;
581
582     sz = (Z_RPNStructure *)odr_malloc(o, sizeof(*sz));
583     switch (li->query_look)
584     {
585     case 'a':
586     case 'o':
587     case 'n':
588     case 'p':
589         sz->which = Z_RPNStructure_complex;
590         if (!(sz->u.complex =
591               rpn_complex(li, o, num_attr, max_attr, attr_list,
592                           attr_clist, attr_set)))
593             return NULL;
594         break;
595     case 't':
596     case 's':
597         sz->which = Z_RPNStructure_simple;
598         if (!(sz->u.simple =
599               rpn_simple(li, o, num_attr, attr_list,
600                          attr_clist, attr_set)))
601             return NULL;
602         break;
603     case 'l':
604         lex(li);
605         if (!li->query_look)
606         {
607             li->error = YAZ_PQF_ERROR_MISSING;
608             return 0;
609         }
610         if (num_attr >= max_attr)
611         {
612             li->error = YAZ_PQF_ERROR_TOOMANY;
613             return 0;
614         }
615         if (!p_query_parse_attr(li, o, num_attr, attr_list,
616                                 attr_clist, attr_set))
617             return 0;
618         num_attr++;
619         lex(li);
620         return
621             rpn_structure(li, o, num_attr, max_attr, attr_list,
622                           attr_clist,  attr_set);
623     case 'y':
624         lex(li);
625         rpn_term_type(li);
626         return
627             rpn_structure(li, o, num_attr, max_attr, attr_list,
628                           attr_clist, attr_set);
629     case 0:                /* operator/operand expected! */
630         li->error = YAZ_PQF_ERROR_MISSING;
631         return 0;
632     }
633     return sz;
634 }
635
636 static Z_RPNQuery *p_query_rpn_mk(ODR o, struct yaz_pqf_parser *li)
637 {
638     Z_RPNQuery *zq;
639     Odr_int attr_array[1024];
640     char *attr_clist[512];
641     Odr_oid *attr_set[512];
642     Odr_oid *top_set = 0;
643
644     zq = (Z_RPNQuery *)odr_malloc(o, sizeof(*zq));
645     lex(li);
646     if (li->query_look == 'r')
647     {
648         lex(li);
649         top_set = query_oid_getvalbyname(li, o);
650         if (!top_set)
651         {
652             li->error = YAZ_PQF_ERROR_ATTSET;
653             return NULL;
654         }
655         lex(li);
656     }
657     if (!top_set)
658     {
659         top_set = odr_oiddup(o, yaz_oid_attset_bib_1);
660     }
661
662     zq->attributeSetId = top_set;
663
664     if (!zq->attributeSetId)
665     {
666         li->error = YAZ_PQF_ERROR_ATTSET;
667         return 0;
668     }
669
670     if (!(zq->RPNStructure = rpn_structure(li, o, 0, 512,
671                                            attr_array, attr_clist, attr_set)))
672         return 0;
673     if (li->query_look)
674     {
675         li->error = YAZ_PQF_ERROR_EXTRA;
676         return 0;
677     }
678     return zq;
679 }
680
681 Z_RPNQuery *p_query_rpn(ODR o, const char *qbuf)
682 {
683     struct yaz_pqf_parser li;
684
685     li.error = 0;
686     li.left_sep = "{\"";
687     li.right_sep = "}\"";
688     li.escape_char = '@';
689     li.term_type = Z_Term_general;
690     li.query_buf = li.query_ptr = qbuf;
691     li.lex_buf = 0;
692     return p_query_rpn_mk(o, &li);
693 }
694
695
696 static Z_AttributeList *p_query_scan_attributes_mk(struct yaz_pqf_parser *li,
697                                              ODR o,
698                                              Odr_oid **attributeSetP)
699 {
700     Odr_int attr_list[1024];
701     char *attr_clist[512];
702     Odr_oid *attr_set[512];
703     int num_attr = 0;
704     int max_attr = 512;
705     Odr_oid *top_set = 0;
706
707     lex(li);
708     if (li->query_look == 'r')
709     {
710         lex(li);
711         top_set = query_oid_getvalbyname(li, o);
712         if (!top_set)
713         {
714             li->error = YAZ_PQF_ERROR_ATTSET;
715             return NULL;
716         }
717         lex(li);
718     }
719     if (!top_set)
720     {
721         top_set = odr_oiddup(o, yaz_oid_attset_bib_1);
722     }
723     *attributeSetP = top_set;
724
725     while (1)
726     {
727         if (li->query_look == 'l')
728         {
729             lex(li);
730             if (!li->query_look)
731             {
732                 li->error = YAZ_PQF_ERROR_MISSING;
733                 return 0;
734             }
735             if (num_attr >= max_attr)
736             {
737                 li->error = YAZ_PQF_ERROR_TOOMANY;
738                 return 0;
739             }
740             if (!p_query_parse_attr(li, o, num_attr, attr_list,
741                                     attr_clist, attr_set))
742                 return 0;
743             num_attr++;
744             lex(li);
745         }
746         else if (li->query_look == 'y')
747         {
748             lex(li);
749             rpn_term_type(li);
750         }
751         else
752             break;
753     }
754     return get_attributeList(o, num_attr, attr_list, attr_clist, attr_set);
755 }
756
757 static Z_AttributesPlusTerm *p_query_scan_mk(struct yaz_pqf_parser *li,
758                                                  ODR o,
759                                                  Odr_oid **attributeSetP)
760 {
761     Z_AttributeList *attr_list = p_query_scan_attributes_mk(li, o, attributeSetP);
762     Z_AttributesPlusTerm *apt;
763
764     if (!li->query_look)
765     {
766         li->error = YAZ_PQF_ERROR_MISSING;
767         return 0;
768     }
769     apt = rpn_term_attributes(li, o, attr_list);
770
771     lex(li);
772
773     if (li->query_look != 0)
774     {
775         li->error = YAZ_PQF_ERROR_EXTRA;
776         return 0;
777     }
778     return apt;
779 }
780
781 YAZ_PQF_Parser yaz_pqf_create(void)
782 {
783     YAZ_PQF_Parser p = (YAZ_PQF_Parser) xmalloc(sizeof(*p));
784
785     p->error = 0;
786     p->left_sep = "{\"";
787     p->right_sep = "}\"";
788     p->escape_char = '@';
789     p->term_type = Z_Term_general;
790
791     return p;
792 }
793
794 void yaz_pqf_destroy(YAZ_PQF_Parser p)
795 {
796     xfree(p);
797 }
798
799 Z_RPNQuery *yaz_pqf_parse(YAZ_PQF_Parser p, ODR o, const char *qbuf)
800 {
801     if (!p)
802         return 0;
803     p->query_buf = p->query_ptr = qbuf;
804     p->lex_buf = 0;
805     return p_query_rpn_mk(o, p);
806 }
807
808 Z_AttributesPlusTerm *yaz_pqf_scan(YAZ_PQF_Parser p, ODR o,
809                                    Odr_oid **attributeSetP,
810                                    const char *qbuf)
811 {
812     if (!p)
813         return 0;
814     p->query_buf = p->query_ptr = qbuf;
815     p->lex_buf = 0;
816     return p_query_scan_mk(p, o, attributeSetP);
817 }
818
819 Z_AttributeList *yaz_pqf_scan_attribute_list(YAZ_PQF_Parser p, ODR o,
820                                    Odr_oid **attributeSetP,
821                                    const char *qbuf)
822 {
823     if (!p)
824         return 0;
825     p->query_buf = p->query_ptr = qbuf;
826     p->lex_buf = 0;
827     return p_query_scan_attributes_mk(p, o, attributeSetP);
828 }
829
830 static Z_FacetField* parse_facet(ODR odr, const char *facet, int length)
831 {
832     YAZ_PQF_Parser pqf_parser = yaz_pqf_create();
833     char *buffer = odr_strdupn(odr, facet, length);
834     Odr_oid *attributeSetId;
835     Z_FacetField *facet_field = 0;
836     Z_AttributeList *attribute_list =
837         yaz_pqf_scan_attribute_list(pqf_parser, odr, &attributeSetId, buffer);
838     
839     if (attribute_list)
840     {
841         facet_field = odr_malloc(odr, sizeof(*facet_field));
842         facet_field->attributes = attribute_list;
843         facet_field->num_terms = 0;
844         facet_field->terms = 0;
845     }
846     yaz_pqf_destroy(pqf_parser);
847     return facet_field;
848 }
849
850 #define FACET_DElIMITER ','
851
852 static int scan_facet_argument(const char *arg) {
853     int index;
854     int length = strlen(arg);
855     int count = 1;
856     for (index = 0; index < length; index++) {
857         if (arg[index] == FACET_DElIMITER)
858             count++;
859     }
860     return count;
861 }
862
863 /**
864  * yax_pdg_parse_facet_list: Parses a comma-separated list of AttributeList(s) into a FacetList.
865  * It does not handle the optional facet term(s).
866  *
867  */
868 Z_FacetList *yaz_pqf_parse_facet_list(ODR odr, const char *facet) {
869     Z_FacetList *facet_list = 0;
870     Z_FacetField  **elements;
871     int index = 0;
872     int num_elements = scan_facet_argument(facet);
873     if (num_elements == 0)
874         return facet_list;
875     facet_list = odr_malloc(odr, sizeof(*facet_list));
876     facet_list->num = num_elements;
877     elements = odr_malloc(odr, num_elements * sizeof(*elements));
878     facet_list->elements = elements;
879     for (index = 0; index < num_elements;) {
880         const char *pos = strchr(facet, FACET_DElIMITER);
881         if (pos == 0)
882             pos = facet + strlen(facet);
883         elements[index] = parse_facet(odr, (const char *) facet, (pos - facet));
884         if (elements[index]) {
885             index++;
886         }
887         else {
888             num_elements--;
889             facet_list->num = num_elements;
890         }
891         facet = pos + 1;
892     }
893     return facet_list;
894 }
895
896
897
898 int yaz_pqf_error(YAZ_PQF_Parser p, const char **msg, size_t *off)
899 {
900     switch (p->error)
901     {
902     case YAZ_PQF_ERROR_NONE:
903         *msg = "no error"; break;
904     case YAZ_PQF_ERROR_EXTRA:
905         *msg = "extra token"; break;
906     case YAZ_PQF_ERROR_MISSING:
907         *msg = "missing token"; break;
908     case YAZ_PQF_ERROR_ATTSET:
909         *msg = "unknown attribute set"; break;
910     case YAZ_PQF_ERROR_TOOMANY:
911         *msg = "too many attributes"; break;
912     case YAZ_PQF_ERROR_BADATTR:
913         *msg = "bad attribute specification"; break;
914     case YAZ_PQF_ERROR_INTERNAL:
915         *msg = "internal error"; break;
916     case YAZ_PQF_ERROR_PROXIMITY:
917         *msg = "proximity error"; break;
918     case YAZ_PQF_ERROR_BAD_INTEGER:
919         *msg = "bad integer"; break;
920     default:
921         *msg = "unknown error"; break;
922     }
923     *off = p->query_ptr - p->query_buf;
924     return p->error;
925 }
926 /*
927  * Local variables:
928  * c-basic-offset: 4
929  * c-file-style: "Stroustrup"
930  * indent-tabs-mode: nil
931  * End:
932  * vim: shiftwidth=4 tabstop=8 expandtab
933  */
934