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