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