YAZ 5.37.0
cqltransform.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
19#if HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <assert.h>
24#include <stdlib.h>
25#include <string.h>
26#include <yaz/rpn2cql.h>
27#include <yaz/xmalloc.h>
28#include <yaz/diagsrw.h>
29#include <yaz/tokenizer.h>
30#include <yaz/wrbuf.h>
31#include <yaz/z-core.h>
32#include <yaz/matchstr.h>
33#include <yaz/oid_db.h>
34#include <yaz/log.h>
35#include <yaz/proxunit.h>
36#include <yaz/snprintf.h>
37
44
52
53
55{
56 cql_transform_t ct = (cql_transform_t) xmalloc(sizeof(*ct));
58 ct->error = 0;
59 ct->addinfo = wrbuf_alloc();
60 ct->entry = 0;
61 ct->nmem = nmem_create();
62 return ct;
63}
64
66 const char *pattern,
68{
69 int ae_num = 0;
70 Z_AttributeElement *ae[20];
71 int ret = 0; /* 0=OK, != 0 FAIL */
72 int t;
73 WRBUF w = wrbuf_alloc();
74
75 t = yaz_tok_move(tp);
76
77 while (t == YAZ_TOK_STRING && ae_num < 20)
78 {
79 WRBUF type_str = wrbuf_alloc();
80 WRBUF set_str = 0;
81 Z_AttributeElement *elem = 0;
82 const char *value_str = 0;
83 /* attset type=value OR type=value */
84
85 elem = (Z_AttributeElement *) nmem_malloc(ct->nmem, sizeof(*elem));
86 elem->attributeSet = 0;
87 ae[ae_num] = elem;
89 wrbuf_puts(type_str, yaz_tok_parse_string(tp));
90 t = yaz_tok_move(tp);
91 if (t == YAZ_TOK_EOF)
92 {
93 wrbuf_destroy(type_str);
94 if (set_str)
95 wrbuf_destroy(set_str);
96 break;
97 }
98 if (t == YAZ_TOK_STRING)
99 {
100 wrbuf_puts(w, " ");
102 set_str = type_str;
103
104 elem->attributeSet =
106 wrbuf_cstr(set_str), ct->nmem);
107
108 type_str = wrbuf_alloc();
109 wrbuf_puts(type_str, yaz_tok_parse_string(tp));
110 t = yaz_tok_move(tp);
111 }
112 elem->attributeType = nmem_intdup(ct->nmem, 0);
113 if (sscanf(wrbuf_cstr(type_str), ODR_INT_PRINTF, elem->attributeType)
114 != 1)
115 {
116 wrbuf_destroy(type_str);
117 if (set_str)
118 wrbuf_destroy(set_str);
119 yaz_log(YLOG_WARN, "Expected numeric attribute type");
120 ret = -1;
121 break;
122 }
123
124 wrbuf_destroy(type_str);
125 if (set_str)
126 wrbuf_destroy(set_str);
127
128 if (t != '=')
129 {
130 yaz_log(YLOG_WARN, "Expected = after after attribute type");
131 ret = -1;
132 break;
133 }
134 t = yaz_tok_move(tp);
135 if (t != YAZ_TOK_STRING) /* value */
136 {
137 yaz_log(YLOG_WARN, "Missing attribute value");
138 ret = -1;
139 break;
140 }
141 value_str = yaz_tok_parse_string(tp);
142 if (yaz_isdigit(*value_str))
143 {
145 elem->value.numeric =
146 nmem_intdup(ct->nmem, atoi(value_str));
147 }
148 else
149 {
151 nmem_malloc(ct->nmem, sizeof(*ca));
153 elem->value.complex = ca;
154 ca->num_list = 1;
155 ca->list = (Z_StringOrNumeric **)
156 nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric *));
157 ca->list[0] = (Z_StringOrNumeric *)
158 nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric));
160 ca->list[0]->u.string = nmem_strdup(ct->nmem, value_str);
161 ca->num_semanticAction = 0;
162 ca->semanticAction = 0;
163 }
164 wrbuf_puts(w, "=");
166 t = yaz_tok_move(tp);
167 wrbuf_puts(w, " ");
168 ae_num++;
169 }
170 if (ret == 0) /* OK? */
171 {
172 struct cql_prop_entry **pp = &ct->entry;
173 while (*pp)
174 pp = &(*pp)->next;
175 *pp = (struct cql_prop_entry *) xmalloc(sizeof(**pp));
176 (*pp)->pattern = xstrdup(pattern);
177 (*pp)->value = xstrdup(wrbuf_cstr(w));
178
179 (*pp)->attr_list.num_attributes = ae_num;
180 if (ae_num == 0)
181 (*pp)->attr_list.attributes = 0;
182 else
183 {
184 (*pp)->attr_list.attributes = (Z_AttributeElement **)
185 nmem_malloc(ct->nmem,
186 ae_num * sizeof(Z_AttributeElement *));
187 memcpy((*pp)->attr_list.attributes, ae,
188 ae_num * sizeof(Z_AttributeElement *));
189 }
190 (*pp)->next = 0;
191
192 if (0)
193 {
195 Z_AttributeList *alp = &(*pp)->attr_list;
197 z_AttributeList(pr, &alp, 0, 0);
198 odr_destroy(pr);
199 }
200 }
201 wrbuf_destroy(w);
202 return ret;
203}
204
206 const char *value)
207{
208 int r;
213 return r;
214}
215
217{
219 if (cql_transform_define_FILE(ct, f))
220 {
222 return 0;
223 }
224 return ct;
225}
226
228{
229 char line[1024];
230 int ret = 0;
231
233 while (ret == 0 && fgets(line, sizeof(line)-1, f))
234 {
236 int t = yaz_tok_move(tp);
237 if (t == YAZ_TOK_STRING)
238 {
239 char *pattern = xstrdup(yaz_tok_parse_string(tp)); /* copy as it's yaz_tok_move resets */
240 t = yaz_tok_move(tp);
241 if (t != '=')
242 ret = -1;
243 else
244 {
246 ret = -1;
247 }
248 xfree(pattern);
249 }
250 else if (t != YAZ_TOK_EOF)
251 {
252 ret = -1;
253 }
255 }
256 return ret;
257}
258
260{
261 struct cql_prop_entry *pe;
262 if (!ct)
263 return;
264 pe = ct->entry;
265 while (pe)
266 {
267 struct cql_prop_entry *pe_next = pe->next;
268 xfree(pe->pattern);
269 xfree(pe->value);
270 xfree(pe);
271 pe = pe_next;
272 }
275 nmem_destroy(ct->nmem);
276 xfree(ct);
277}
278
280{
282 if (cql_transform_define_fname(ct, fname))
283 {
285 return 0;
286 }
287 return ct;
288}
289
291{
292 int ret;
293 FILE *f = fopen(fname, "r");
294 if (!f)
295 return -2;
296 ret = cql_transform_define_FILE(ct, f);
297 fclose(f);
298 return ret;
299}
300
301#if 0
302struct Z_AttributeElement {
304 int *attributeType;
305 int which;
306 union {
307 int *numeric;
309#define Z_AttributeValue_numeric 1
310#define Z_AttributeValue_complex 2
311 } value;
312};
313#endif
314
316{
319 int len_a, len_b;
320 char *buf_a, *buf_b;
321 int ret;
322
323 z_AttributeElement(odr_a, &a, 0, 0);
324 z_AttributeElement(odr_b, &b, 0, 0);
325
326 buf_a = odr_getbuf(odr_a, &len_a, 0);
327 buf_b = odr_getbuf(odr_b, &len_b, 0);
328
329 ret = yaz_memcmp(buf_a, buf_b, len_a, len_b);
330
331 odr_destroy(odr_a);
332 odr_destroy(odr_b);
333 return ret;
334}
335
337 const char *category,
338 Z_AttributeList *attributes)
339{
340 struct cql_prop_entry *e;
341 size_t clen = strlen(category);
342 for (e = ct->entry; e; e = e->next)
343 {
344 if (!strncmp(e->pattern, category, clen))
345 {
346 /* category matches.. See if attributes in pattern value
347 are all listed in actual attributes */
348 int i;
349 for (i = 0; i < e->attr_list.num_attributes; i++)
350 {
351 /* entry attribute */
353 int j;
354 for (j = 0; j < attributes->num_attributes; j++)
355 {
356 /* actual attribute */
357 Z_AttributeElement a_ae = *attributes->attributes[j];
358 if (!compare_attr(e_ae, &a_ae))
359 break;
360 if (a_ae.attributeSet &&
362 a_ae.attributeSet = 0;
363 if (!compare_attr(e_ae, &a_ae))
364 break;
365 }
366 if (j == attributes->num_attributes)
367 break; /* i was not found at all.. try next pattern */
368
369 }
370 if (i == e->attr_list.num_attributes)
371 return e->pattern + clen;
372 }
373 }
374 return 0;
375}
376
378 const char *pat1, const char *pat2,
379 const char *pat3)
380{
381 char pattern[120];
382 struct cql_prop_entry *e;
383
384 if (pat1 && pat2 && pat3)
385 yaz_snprintf(pattern, sizeof pattern, "%s.%s.%s", pat1, pat2, pat3);
386 else if (pat1 && pat2)
387 yaz_snprintf(pattern, sizeof pattern, "%s.%s", pat1, pat2);
388 else if (pat1 && pat3)
389 yaz_snprintf(pattern, sizeof pattern, "%s.%s", pat1, pat3);
390 else if (pat1)
391 yaz_snprintf(pattern, sizeof pattern, "%s", pat1);
392 else
393 return 0;
394
395 for (e = ct->entry; e; e = e->next)
396 {
397 if (!cql_strcmp(e->pattern, pattern))
398 return e->value;
399 }
400 return 0;
401}
402
403int cql_pr_attr_uri(cql_transform_t ct, WRBUF addinfo, const char *category,
404 const char *uri, const char *val, const char *default_val,
405 void (*pr)(const char *buf, void *client_data),
406 void *client_data,
407 int errcode)
408{
409 const char *res = 0;
410 const char *eval = val ? val : default_val;
411 const char *prefix = 0;
412
413 if (uri)
414 {
415 struct cql_prop_entry *e;
416
417 for (e = ct->entry; e; e = e->next)
418 if (!memcmp(e->pattern, "set.", 4) && e->value &&
419 !strcmp(e->value, uri))
420 {
421 prefix = e->pattern+4;
422 break;
423 }
424 /* must have a prefix now - if not it's an error */
425 }
426
427 if (!uri || prefix)
428 {
429 if (!res)
430 res = cql_lookup_property(ct, category, prefix, eval);
431 /* we have some aliases for some relations unfortunately.. */
432 if (!res && !prefix && !strcmp(category, "relation"))
433 {
434 if (!strcmp(val, "=="))
435 res = cql_lookup_property(ct, category, prefix, "exact");
436 if (!strcmp(val, "="))
437 res = cql_lookup_property(ct, category, prefix, "eq");
438 if (!strcmp(val, "<="))
439 res = cql_lookup_property(ct, category, prefix, "le");
440 if (!strcmp(val, ">="))
441 res = cql_lookup_property(ct, category, prefix, "ge");
442 }
443 if (!res)
444 res = cql_lookup_property(ct, category, prefix, "*");
445 }
446 if (res)
447 {
448 char buf[64];
449
450 const char *cp0 = res, *cp1;
451 while ((cp1 = strchr(cp0, '=')))
452 {
453 int i;
454 while (*cp1 && *cp1 != ' ')
455 cp1++;
456 if (cp1 - cp0 >= (ptrdiff_t) sizeof(buf))
457 break;
458 memcpy(buf, cp0, cp1 - cp0);
459 buf[cp1-cp0] = 0;
460 (*pr)("@attr ", client_data);
461
462 for (i = 0; buf[i]; i++)
463 {
464 if (buf[i] == '*')
465 (*pr)(eval, client_data);
466 else
467 {
468 char tmp[2];
469 tmp[0] = buf[i];
470 tmp[1] = '\0';
471 (*pr)(tmp, client_data);
472 }
473 }
474 (*pr)(" ", client_data);
475 cp0 = cp1;
476 while (*cp0 == ' ')
477 cp0++;
478 }
479 return 0;
480 }
481 /* error ... */
482 if (errcode == 0)
483 return 1; /* signal error, but do not set addinfo */
484 if (val)
485 wrbuf_puts(addinfo, val);
486 return errcode;
487}
488
489int cql_pr_attr(cql_transform_t ct, WRBUF addinfo, const char *category,
490 const char *val, const char *default_val,
491 void (*pr)(const char *buf, void *client_data),
492 void *client_data,
493 int errcode)
494{
495 return cql_pr_attr_uri(ct, addinfo, category, 0 /* uri */,
496 val, default_val, pr, client_data, errcode);
497}
498
499
500static void cql_pr_int(int val,
501 void (*pr)(const char *buf, void *client_data),
502 void *client_data)
503{
504 char buf[21]; /* enough characters to 2^64 */
505 yaz_snprintf(buf, sizeof buf, "%d", val);
506 (*pr)(buf, client_data);
507 (*pr)(" ", client_data);
508}
509
510
511static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods,
512 WRBUF addinfo,
513 void (*pr)(const char *buf, void *client_data),
514 void *client_data)
515{
516 int exclusion = 0;
517 int distance = -1;
518 int ordered = 0;
519 int proxrel = 2; /* less than or equal */
520 int unit = 2; /* word */
521
522 while (mods)
523 {
524 const char *name = mods->u.st.index;
525 const char *term = mods->u.st.term;
526 const char *relation = mods->u.st.relation;
527
528 if (!strcmp(name, "distance")) {
529 distance = strtol(term, (char**) 0, 0);
530 if (!strcmp(relation, "="))
531 proxrel = 3;
532 else if (!strcmp(relation, ">"))
533 proxrel = 5;
534 else if (!strcmp(relation, "<"))
535 proxrel = 1;
536 else if (!strcmp(relation, ">="))
537 proxrel = 4;
538 else if (!strcmp(relation, "<="))
539 proxrel = 2;
540 else if (!strcmp(relation, "<>"))
541 proxrel = 6;
542 else
543 {
544 wrbuf_puts(addinfo, relation);
546 }
547 }
548 else if (!strcmp(name, "ordered"))
549 ordered = 1;
550 else if (!strcmp(name, "unordered"))
551 ordered = 0;
552 else if (!strcmp(name, "unit"))
553 {
554 unit = z_str_to_ProxUnit(term);
555 if (unit == 0)
556 {
557 wrbuf_puts(addinfo, term);
559 }
560 }
561 else
562 {
563 wrbuf_puts(addinfo, name);
565 }
566 mods = mods->u.st.modifiers;
567 }
568
569 if (distance == -1)
570 distance = (unit == 2) ? 1 : 0;
571
572 cql_pr_int(exclusion, pr, client_data);
573 cql_pr_int(distance, pr, client_data);
574 cql_pr_int(ordered, pr, client_data);
575 cql_pr_int(proxrel, pr, client_data);
576 (*pr)("k ", client_data);
577 cql_pr_int(unit, pr, client_data);
578
579 return 0;
580}
581
582/* ### checks for CQL relation-name rather than Type-1 attribute */
583static int has_modifier(struct cql_node *cn, const char *name) {
584 struct cql_node *mod;
585 for (mod = cn->u.st.modifiers; mod != 0; mod = mod->u.st.modifiers) {
586 if (!mod->u.st.term && !strcmp(mod->u.st.index, name))
587 return 1;
588 }
589
590 return 0;
591}
592
594 struct cql_node *cn, WRBUF addinfo,
595 const char *term, int length,
596 void (*pr)(const char *buf, void *client_data),
597 void *client_data)
598{
599 int i, r;
600 const char *ns = cn->u.st.index_uri;
601 int z3958_mode = 0;
602 int process_term = 1;
603
604
605 if (has_modifier(cn, "regexp"))
606 process_term = 0;
607 else if (has_modifier(cn, "unmasked"))
608 process_term = 0;
609 else if (cql_lookup_property(ct, "truncation", 0, "cql"))
610 {
611 process_term = 0;
612 r = cql_pr_attr(ct, addinfo, "truncation", "cql", 0,
613 pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
614 if (r)
615 return r;
616 }
617 assert(cn->which == CQL_NODE_ST);
618
619 if (process_term)
620 { /* convert term via truncation.things */
621 unsigned anchor = 0;
622 unsigned trunc = 0;
623 for (i = 0; i < length; i++)
624 {
625 if (term[i] == '\\' && i < length - 1)
626 i++;
627 else
628 {
629 switch (term[i])
630 {
631 case '^':
632 if (i == 0)
633 anchor |= 1;
634 else if (i == length - 1)
635 anchor |= 2;
636 break;
637 case '*':
638 if (i == 0)
639 trunc |= 1;
640 else if (i == length - 1)
641 trunc |= 2;
642 else
643 z3958_mode = 1;
644 break;
645 case '?':
646 z3958_mode = 1;
647 break;
648 }
649 }
650 }
651 if (anchor == 3)
652 {
653 r = cql_pr_attr(ct, addinfo, "position", "firstAndLast", 0,
654 pr, client_data,
656 if (r)
657 return r;
658 term++;
659 length -= 2;
660 }
661 else if (anchor == 1)
662 {
663 r = cql_pr_attr(ct, addinfo, "position", "first", 0,
664 pr, client_data,
666 if (r)
667 return r;
668 term++;
669 length--;
670 }
671 else if (anchor == 2)
672 {
673 r = cql_pr_attr(ct, addinfo, "position", "last", 0,
674 pr, client_data,
676 if (r)
677 return r;
678 length--;
679 }
680 else
681 {
682 r = cql_pr_attr(ct, addinfo, "position", "any", 0,
683 pr, client_data,
685 if (r)
686 return r;
687 }
688 if (z3958_mode == 0)
689 {
690 if (trunc == 3 && !cql_pr_attr(ct, addinfo, "truncation",
691 "both", 0, pr, client_data, 0))
692 {
693 term++;
694 length -= 2;
695 }
696 else if (trunc == 1 && !cql_pr_attr(ct, addinfo, "truncation",
697 "left", 0, pr, client_data, 0))
698 {
699 term++;
700 length--;
701 }
702 else if (trunc == 2 && !cql_pr_attr(ct, addinfo, "truncation",
703 "right", 0, pr, client_data, 0))
704 {
705 length--;
706 }
707 else if (trunc)
708 z3958_mode = 1;
709 else
710 cql_pr_attr(ct, addinfo, "truncation", "none", 0,
711 pr, client_data, 0);
712 }
713 if (z3958_mode)
714 {
715 r = cql_pr_attr(ct, addinfo, "truncation", "z3958", 0,
716 pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
717 if (r)
718 return r;
719 }
720 }
721 if (ns)
722 {
723 r = cql_pr_attr_uri(ct, addinfo, "index", ns,
724 cn->u.st.index, "serverChoice",
725 pr, client_data, YAZ_SRW_UNSUPP_INDEX);
726 if (r)
727 return r;
728 }
729 if (cn->u.st.modifiers)
730 {
731 struct cql_node *mod = cn->u.st.modifiers;
732 for (; mod; mod = mod->u.st.modifiers)
733 {
734 if (!mod->u.st.term)
735 {
736 r = cql_pr_attr(ct, addinfo,
737 "relationModifier", mod->u.st.index, 0,
738 pr, client_data,
740 if (r)
741 return r;
742 }
743 }
744 }
745 (*pr)("\"", client_data);
746 if (process_term)
747 for (i = 0; i < length; i++)
748 {
749 char x[2]; /* temp buffer */
750 if (term[i] == '\\' && i < length - 1)
751 {
752 i++;
753 if (strchr("\"\\", term[i]))
754 pr("\\", client_data);
755 if (z3958_mode && strchr("#?", term[i]))
756 pr("\\\\", client_data); /* double \\ to survive PQF parse */
757 x[0] = term[i];
758 x[1] = '\0';
759 pr(x, client_data);
760 }
761 else if (z3958_mode && term[i] == '*')
762 {
763 pr("?", client_data);
764 if (i < length - 1 && yaz_isdigit(term[i+1]))
765 pr("\\\\", client_data); /* dbl \\ to survive PQF parse */
766 }
767 else if (z3958_mode && term[i] == '?')
768 {
769 pr("#", client_data);
770 }
771 else
772 {
773 if (term[i] == '\"')
774 pr("\\", client_data);
775 if (z3958_mode && strchr("#?", term[i]))
776 pr("\\\\", client_data); /* dbl \\ to survive PQF parse */
777 x[0] = term[i];
778 x[1] = '\0';
779 pr(x, client_data);
780 }
781 }
782 else
783 {
784 for (i = 0; i < length; i++)
785 {
786 char x[2];
787 x[0] = term[i];
788 x[1] = '\0';
789 pr(x, client_data);
790 }
791 }
792 (*pr)("\" ", client_data);
793 return 0;
794}
795
796static int emit_terms(cql_transform_t ct, struct cql_node *cn,
797 WRBUF addinfo,
798 void (*pr)(const char *buf, void *client_data),
799 void *client_data,
800 const char *op)
801{
802 struct cql_node *ne = cn->u.st.extra_terms;
803 int r;
804 if (ne)
805 {
806 (*pr)("@", client_data);
807 (*pr)(op, client_data);
808 (*pr)(" ", client_data);
809 }
810 r = emit_term(ct, cn, addinfo, cn->u.st.term, strlen(cn->u.st.term),
811 pr, client_data);
812 for (; !r && ne; ne = ne->u.st.extra_terms)
813 {
814 if (ne->u.st.extra_terms)
815 {
816 (*pr)("@", client_data);
817 (*pr)(op, client_data);
818 (*pr)(" ", client_data);
819 }
820 r = emit_term(ct, cn, addinfo, ne->u.st.term, strlen(ne->u.st.term),
821 pr, client_data);
822 }
823 return r;
824}
825
826static int emit_wordlist(cql_transform_t ct, struct cql_node *cn,
827 WRBUF addinfo,
828 void (*pr)(const char *buf, void *client_data),
829 void *client_data,
830 const char *op)
831{
832 int r = 0;
833 const char *cp0 = cn->u.st.term;
834 const char *cp1;
835 const char *last_term = 0;
836 int last_length = 0;
837 while (!r && cp0)
838 {
839 while (*cp0 == ' ')
840 cp0++;
841 cp1 = strchr(cp0, ' ');
842 if (last_term)
843 {
844 (*pr)("@", client_data);
845 (*pr)(op, client_data);
846 (*pr)(" ", client_data);
847 r = emit_term(ct, cn, addinfo, last_term, last_length,
848 pr, client_data);
849 }
850 last_term = cp0;
851 if (cp1)
852 last_length = cp1 - cp0;
853 else
854 last_length = strlen(cp0);
855 cp0 = cp1;
856 }
857 if (!r && last_term)
858 r = emit_term(ct, cn, addinfo, last_term, last_length, pr, client_data);
859 return r;
860}
861
862static int emit_node(cql_transform_t ct, struct cql_node *cn,
863 WRBUF addinfo,
864 void (*pr)(const char *buf, void *client_data),
865 void *client_data)
866{
867 const char *ns;
868 int r = 0;
869 struct cql_node *mods;
870
871 if (!cn)
872 return 0;
873 switch (cn->which)
874 {
875 case CQL_NODE_ST:
876 ns = cn->u.st.index_uri;
877 if (ns)
878 {
879 if (!strcmp(ns, cql_uri())
880 && cn->u.st.index && !cql_strcmp(cn->u.st.index, "resultSet"))
881 {
882 (*pr)("@set \"", client_data);
883 (*pr)(cn->u.st.term, client_data);
884 (*pr)("\" ", client_data);
885 return 0;
886 }
887 }
888 else
889 {
891 }
892 if (cn->u.st.modifiers)
893 {
894 struct cql_node *mod = cn->u.st.modifiers;
895 for (; mod; mod = mod->u.st.modifiers)
896 {
897 if (mod->u.st.term) /* only modifiers with name+value */
898 {
899 /* only relation = supported at the moment */
900 if (mod->u.st.relation && strcmp(mod->u.st.relation, "="))
901 {
902 wrbuf_puts(addinfo, mod->u.st.relation);
904 }
905 pr("@prox 0 0 0 0 k 8 ", client_data);
906 }
907 }
908 }
909 cql_pr_attr(ct, addinfo, "always", 0, 0, pr, client_data, 0);
910 r = cql_pr_attr(ct, addinfo, "relation", cn->u.st.relation, 0,
911 pr, client_data, YAZ_SRW_UNSUPP_RELATION);
912 if (r)
913 return r;
914 r = cql_pr_attr(ct, addinfo, "structure", cn->u.st.relation, 0,
915 pr, client_data,
917 if (r)
918 return r;
919 if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "all"))
920 r = emit_wordlist(ct, cn, addinfo, pr, client_data, "and");
921 else if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "any"))
922 r = emit_wordlist(ct, cn, addinfo, pr, client_data, "or");
923 else
924 r = emit_terms(ct, cn, addinfo, pr, client_data, "and");
925
926 if (cn->u.st.modifiers)
927 {
928 struct cql_node *mod = cn->u.st.modifiers;
929 for (; mod; mod = mod->u.st.modifiers)
930 {
931 if (mod->u.st.term)
932 {
933 r = cql_pr_attr_uri(ct, addinfo, "index",
934 mod->u.st.index_uri,
935 mod->u.st.index, "serverChoice",
936 pr, client_data, YAZ_SRW_UNSUPP_INDEX);
937 if (r)
938 return r;
939 pr(mod->u.st.term, client_data);
940 pr(" ", client_data);
941 }
942 }
943 }
944 break;
945 case CQL_NODE_BOOL:
946 (*pr)("@", client_data);
947 (*pr)(cn->u.boolean.value, client_data);
948 (*pr)(" ", client_data);
949 mods = cn->u.boolean.modifiers;
950 if (!strcmp(cn->u.boolean.value, "prox"))
951 {
952 r = cql_pr_prox(ct, mods, addinfo, pr, client_data);
953 if (r)
954 return r;
955 }
956 else if (mods)
957 {
958 /* Boolean modifiers other than on proximity not supported */
959 wrbuf_puts(addinfo, mods->u.st.index);
961 }
962
963 r = emit_node(ct, cn->u.boolean.left, addinfo, pr, client_data);
964 if (r)
965 return r;
966 r = emit_node(ct, cn->u.boolean.right, addinfo, pr, client_data);
967 if (r)
968 return r;
969 break;
970 case CQL_NODE_SORT:
971 r = emit_node(ct, cn->u.sort.search, addinfo, pr, client_data);
972 break;
973 default:
974 fprintf(stderr, "Fatal: impossible CQL node-type %d\n", cn->which);
975 abort();
976 }
977 return r;
978}
979
981 WRBUF addinfo,
982 void (*pr)(const char *buf, void *client_data),
983 void *client_data)
984{
985 struct cql_prop_entry *e;
986 NMEM nmem = nmem_create();
987 int r;
988
989 for (e = ct->entry; e ; e = e->next)
990 {
991 if (!cql_strncmp(e->pattern, "set.", 4))
992 cql_apply_prefix(nmem, cn, e->pattern+4, e->value);
993 else if (!cql_strcmp(e->pattern, "set"))
994 cql_apply_prefix(nmem, cn, 0, e->value);
995 }
996 r = emit_node(ct, cn, addinfo, pr, client_data);
997 nmem_destroy(nmem);
998 return r;
999}
1000
1002 void (*pr)(const char *buf, void *client_data),
1003 void *client_data)
1004{
1005 WRBUF addinfo = wrbuf_alloc();
1006 int r = cql_transform_r(ct, cn, addinfo, pr, client_data);
1007 cql_transform_set_error(ct, r, wrbuf_cstr(addinfo));
1008 wrbuf_destroy(addinfo);
1009 return r;
1010}
1011
1012int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f)
1013{
1014 return cql_transform(ct, cn, cql_fputs, f);
1015}
1016
1018 char *out, int max)
1019{
1020 struct cql_buf_write_info info;
1021 int r;
1022
1023 info.off = 0;
1024 info.max = max;
1025 info.buf = out;
1026 r = cql_transform(ct, cn, cql_buf_write_handler, &info);
1027 if (info.off < 0) {
1028 /* Attempt to write past end of buffer. For some reason, this
1029 SRW diagnostic is deprecated, but it's so perfect for our
1030 purposes that it would be stupid not to use it. */
1031 char numbuf[30];
1032 yaz_snprintf(numbuf, sizeof numbuf, "%ld", (long) info.max);
1034 return -1;
1035 }
1036 if (info.off >= 0)
1037 info.buf[info.off] = '\0';
1038 return r;
1039}
1040
1041int cql_transform_error(cql_transform_t ct, const char **addinfo)
1042{
1043 *addinfo = wrbuf_len(ct->addinfo) ? wrbuf_cstr(ct->addinfo) : 0;
1044 return ct->error;
1045}
1046
1047void cql_transform_set_error(cql_transform_t ct, int error, const char *addinfo)
1048{
1049 wrbuf_rewind(ct->addinfo);
1050 if (addinfo)
1051 wrbuf_puts(ct->addinfo, addinfo);
1052 ct->error = error;
1053}
1054
1055/*
1056 * Local variables:
1057 * c-basic-offset: 4
1058 * c-file-style: "Stroustrup"
1059 * indent-tabs-mode: nil
1060 * End:
1061 * vim: shiftwidth=4 tabstop=8 expandtab
1062 */
#define CQL_NODE_SORT
Node type: sortby single spec.
Definition cql.h:115
struct cql_transform_t_ * cql_transform_t
CQL transform handle. The transform describes how to convert from CQL to PQF (Type-1 AKA RPN).
Definition cql.h:292
#define CQL_NODE_ST
Node type: search term.
Definition cql.h:111
#define CQL_NODE_BOOL
Node type: boolean.
Definition cql.h:113
int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f)
transforms PQF given a CQL tree from FILE (not re-entrant)
static int emit_term(cql_transform_t ct, struct cql_node *cn, WRBUF addinfo, const char *term, int length, void(*pr)(const char *buf, void *client_data), void *client_data)
static const char * cql_lookup_property(cql_transform_t ct, const char *pat1, const char *pat2, const char *pat3)
static int has_modifier(struct cql_node *cn, const char *name)
int cql_pr_attr_uri(cql_transform_t ct, WRBUF addinfo, const char *category, const char *uri, const char *val, const char *default_val, void(*pr)(const char *buf, void *client_data), void *client_data, int errcode)
static int cql_transform_parse_tok_line(cql_transform_t ct, const char *pattern, yaz_tok_parse_t tp)
cql_transform_t cql_transform_create(void)
creates a CQL transform handle
static void cql_pr_int(int val, void(*pr)(const char *buf, void *client_data), void *client_data)
int cql_transform_define_FILE(cql_transform_t ct, FILE *f)
extends transform from opened file
static int compare_attr(Z_AttributeElement *a, Z_AttributeElement *b)
int cql_transform(cql_transform_t ct, struct cql_node *cn, void(*pr)(const char *buf, void *client_data), void *client_data)
tranforms PQF given a CQL tree (NOT re-entrant)
cql_transform_t cql_transform_open_FILE(FILE *f)
creates a CQL transform handle from an opened file handle
static int emit_terms(cql_transform_t ct, struct cql_node *cn, WRBUF addinfo, void(*pr)(const char *buf, void *client_data), void *client_data, const char *op)
int cql_pr_attr(cql_transform_t ct, WRBUF addinfo, const char *category, const char *val, const char *default_val, void(*pr)(const char *buf, void *client_data), void *client_data, int errcode)
void cql_transform_set_error(cql_transform_t ct, int error, const char *addinfo)
sets error and addinfo for transform
cql_transform_t cql_transform_open_fname(const char *fname)
creates a CQL transform handle from a file
static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods, WRBUF addinfo, void(*pr)(const char *buf, void *client_data), void *client_data)
int cql_transform_define_fname(cql_transform_t ct, const char *fname)
extends transform from a file
int cql_transform_buf(cql_transform_t ct, struct cql_node *cn, char *out, int max)
transforms PQF given a CQL tree from buffer (not re-entrant)
void cql_transform_close(cql_transform_t ct)
destroys a CQL transform handle
static int emit_wordlist(cql_transform_t ct, struct cql_node *cn, WRBUF addinfo, void(*pr)(const char *buf, void *client_data), void *client_data, const char *op)
int cql_transform_define_pattern(cql_transform_t ct, const char *pattern, const char *value)
defines CQL transform pattern
int cql_transform_error(cql_transform_t ct, const char **addinfo)
returns additional information for last transform
int cql_transform_r(cql_transform_t ct, struct cql_node *cn, WRBUF addinfo, void(*pr)(const char *buf, void *client_data), void *client_data)
tranforms PQF given a CQL tree (re-entrant)
static int emit_node(cql_transform_t ct, struct cql_node *cn, WRBUF addinfo, void(*pr)(const char *buf, void *client_data), void *client_data)
const char * cql_lookup_reverse(cql_transform_t ct, const char *category, Z_AttributeList *attributes)
find a pattern that has a subset of attributes
int cql_strcmp(const char *s1, const char *s2)
compares two CQL strings (ala strcmp)
Definition cqlutil.c:194
int cql_strncmp(const char *s1, const char *s2, size_t n)
compares two CQL strings (ala strncmp)
Definition cqlutil.c:210
struct cql_node * cql_apply_prefix(NMEM nmem, struct cql_node *n, const char *prefix, const char *uri)
applies a prefix+uri to "unresolved" index and relation URIs. "unresolved" URIs are those nodes where...
Definition cqlutil.c:110
void cql_fputs(const char *buf, void *client_data)
stream handle for file (used by cql_to_xml_stdio)
Definition cqlutil.c:18
const char * cql_uri(void)
returns the standard CQL context set URI.
Definition cqlutil.c:105
Diagnostics: Generated by csvtodiag.tcl from ./srw.csv.
#define YAZ_SRW_UNSUPP_PROX_RELATION
Definition diagsrw.h:48
#define YAZ_SRW_UNSUPP_CONTEXT_SET
Definition diagsrw.h:23
#define YAZ_SRW_UNSUPP_INDEX
Definition diagsrw.h:24
#define YAZ_SRW_MASKING_CHAR_UNSUPP
Definition diagsrw.h:36
#define YAZ_SRW_UNSUPP_PROX_UNIT
Definition diagsrw.h:50
#define YAZ_SRW_UNSUPP_BOOLEAN_MODIFIER
Definition diagsrw.h:54
#define YAZ_SRW_UNSUPP_RELATION
Definition diagsrw.h:27
#define YAZ_SRW_ANCHORING_CHAR_IN_UNSUPP_POSITION
Definition diagsrw.h:40
#define YAZ_SRW_TOO_MANY_CHARS_IN_QUERY
Definition diagsrw.h:20
#define YAZ_SRW_UNSUPP_RELATION_MODIFIER
Definition diagsrw.h:28
#define YAZ_SRW_UNSUPP_COMBI_OF_RELATION_AND_TERM
Definition diagsrw.h:32
char * name
Definition initopt.c:18
void yaz_log(int level, const char *fmt,...)
Writes log message.
Definition log.c:487
FILE * yaz_log_file(void)
returns FILE handle for log or NULL if no file is in use
Definition log.c:138
Logging utility.
#define YLOG_WARN
log level: warning
Definition log.h:46
int yaz_memcmp(const void *a, const void *b, size_t len_a, size_t len_b)
compares two buffers of different size
Definition matchstr.c:86
Header for YAZ iconv interface.
NMEM nmem_create(void)
returns new NMEM handle
Definition nmem.c:181
void * nmem_malloc(NMEM n, size_t size)
allocates memory block on NMEM handle
Definition nmem.c:145
void nmem_destroy(NMEM n)
destroys NMEM handle and memory associated with it
Definition nmem.c:204
struct nmem_control * NMEM
NMEM handle (an opaque pointer to memory).
Definition nmem.h:44
nmem_int_t * nmem_intdup(NMEM mem, nmem_int_t v)
allocates and sets integer for NMEM
Definition nmemsdup.c:42
char * nmem_strdup(NMEM mem, const char *src)
allocates string on NMEM handle (similar strdup)
Definition nmemsdup.c:19
void odr_setprint_noclose(ODR o, FILE *file)
Definition odr.c:167
char * odr_getbuf(ODR o, int *len, int *size)
Definition odr.c:275
ODR odr_createmem(int direction)
Definition odr.c:198
void odr_destroy(ODR o)
Definition odr.c:251
#define ODR_INT_PRINTF
Definition odr.h:49
struct odr * ODR
Definition odr.h:121
#define ODR_PRINT
Definition odr.h:97
#define ODR_ENCODE
Definition odr.h:96
Odr_oid * yaz_string_to_oid_nmem(yaz_oid_db_t oid_list, oid_class oclass, const char *name, NMEM nmem)
creates NMEM malloc'ed OID from string
Definition oid_db.c:63
yaz_oid_db_t yaz_oid_std(void)
returns standard OID database
Definition oid_db.c:33
Header for OID database.
@ CLASS_ATTSET
Definition oid_db.h:50
const Odr_oid yaz_oid_attset_bib_1[]
Definition oid_std.c:13
int oid_oidcmp(const Odr_oid *o1, const Odr_oid *o2)
compares OIDs
Definition oid_util.c:34
int z_str_to_ProxUnit(const char *str)
converts unit name string to unit integer
Definition proxunit.c:40
Header for JSON functions.
Header for RPN to CQL tranform.
void yaz_snprintf(char *buf, size_t size, const char *fmt,...)
Definition snprintf.c:31
Header for config file reading utilities.
Odr_int * attributeType
Definition z-core.h:581
Z_ComplexAttribute * complex
Definition z-core.h:585
Z_AttributeSetId * attributeSet
Definition z-core.h:580
Odr_int * numeric
Definition z-core.h:584
union Z_AttributeElement::@260252174261265367116362007076255375270002041323 value
int num_attributes
Definition z-core.h:532
Z_AttributeElement ** attributes
Definition z-core.h:533
Z_StringOrNumeric ** list
Definition z-core.h:574
Odr_int ** semanticAction
Definition z-core.h:576
union Z_StringOrNumeric::@255321135104110073015132067151226017215302214211 u
Z_InternationalString * string
Definition z-core.h:1321
Structure used by cql_buf_write_handler.
Definition cql.h:170
CQL parse tree (node).
Definition cql.h:119
struct cql_node::@103257335133214234142137075341003020020243260314::@231337216262210265241053375071103126222160053350 st
struct cql_node * right
Definition cql.h:147
char * value
Definition cql.h:143
struct cql_node * search
Definition cql.h:159
union cql_node::@103257335133214234142137075341003020020243260314 u
struct cql_node * extra_terms
Definition cql.h:138
struct cql_node::@103257335133214234142137075341003020020243260314::@240210333203360145104277071333350273146264012233 boolean
struct cql_node * modifiers
Definition cql.h:136
int which
Definition cql.h:121
char * relation
Definition cql.h:132
struct cql_node::@103257335133214234142137075341003020020243260314::@115152140343061015107127141216014153002063077012 sort
char * index
Definition cql.h:126
char * index_uri
Definition cql.h:128
struct cql_node * left
Definition cql.h:145
char * term
Definition cql.h:130
char * pattern
Z_AttributeList attr_list
struct cql_prop_entry * next
char * value
yaz_tok_cfg_t tok_cfg
struct cql_prop_entry * entry
yaz_tok_parse_t yaz_tok_parse_buf(yaz_tok_cfg_t t, const char *buf)
Definition tokenizer.c:83
yaz_tok_cfg_t yaz_tok_cfg_create(void)
Definition tokenizer.c:45
void yaz_tok_parse_destroy(yaz_tok_parse_t tp)
Definition tokenizer.c:123
void yaz_tok_cfg_single_tokens(yaz_tok_cfg_t t, const char *simple)
Definition tokenizer.c:39
void yaz_tok_cfg_destroy(yaz_tok_cfg_t t)
Definition tokenizer.c:57
const char * yaz_tok_parse_string(yaz_tok_parse_t tp)
Definition tokenizer.c:174
int yaz_tok_move(yaz_tok_parse_t tp)
Definition tokenizer.c:130
Header with public definitions about YAZ' tokenizer.
struct yaz_tok_parse * yaz_tok_parse_t
Definition tokenizer.h:44
#define YAZ_TOK_EOF
Definition tokenizer.h:38
#define YAZ_TOK_STRING
Definition tokenizer.h:40
struct yaz_tok_cfg * yaz_tok_cfg_t
Definition tokenizer.h:43
void wrbuf_destroy(WRBUF b)
destroy WRBUF and its buffer
Definition wrbuf.c:38
const char * wrbuf_cstr(WRBUF b)
returns WRBUF content as C-string
Definition wrbuf.c:299
void wrbuf_rewind(WRBUF b)
empty WRBUF content (length of buffer set to 0)
Definition wrbuf.c:47
WRBUF wrbuf_alloc(void)
construct WRBUF
Definition wrbuf.c:25
void wrbuf_puts(WRBUF b, const char *buf)
appends C-string to WRBUF
Definition wrbuf.c:89
Header for WRBUF (growing buffer).
#define wrbuf_len(b)
Definition wrbuf.h:269
struct wrbuf * WRBUF
void cql_buf_write_handler(const char *b, void *client_data)
Handler for cql_buf_write_info.
Definition xcqlutil.c:251
Header for memory handling functions.
#define xstrdup(s)
utility macro which calls xstrdup_f
Definition xmalloc.h:55
#define xfree(x)
utility macro which calls xfree_f
Definition xmalloc.h:53
#define xmalloc(x)
utility macro which calls malloc_f
Definition xmalloc.h:49
#define yaz_isdigit(x)
Definition yaz-iconv.h:86
ASN.1 Module Z39-50-APDU-1995.
#define Z_AttributeValue_numeric
Definition z-core.h:586
int z_AttributeList(ODR o, Z_AttributeList **p, int opt, const char *name)
Definition z-core.c:316
#define Z_AttributeValue_complex
Definition z-core.h:587
#define Z_StringOrNumeric_string
Definition z-core.h:1323
int z_AttributeElement(ODR o, Z_AttributeElement **p, int opt, const char *name)
Definition z-core.c:398
Odr_oid Z_AttributeSetId
Definition z-core.h:283
struct Z_ComplexAttribute Z_ComplexAttribute
Definition z-core.h:73