YAZ 5.35.1
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
43
51
52
54{
55 cql_transform_t ct = (cql_transform_t) xmalloc(sizeof(*ct));
57 ct->error = 0;
58 ct->addinfo = wrbuf_alloc();
59 ct->entry = 0;
60 ct->nmem = nmem_create();
61 return ct;
62}
63
65 const char *pattern,
67{
68 int ae_num = 0;
69 Z_AttributeElement *ae[20];
70 int ret = 0; /* 0=OK, != 0 FAIL */
71 int t;
72 WRBUF w = wrbuf_alloc();
73
74 t = yaz_tok_move(tp);
75
76 while (t == YAZ_TOK_STRING && ae_num < 20)
77 {
78 WRBUF type_str = wrbuf_alloc();
79 WRBUF set_str = 0;
80 Z_AttributeElement *elem = 0;
81 const char *value_str = 0;
82 /* attset type=value OR type=value */
83
84 elem = (Z_AttributeElement *) nmem_malloc(ct->nmem, sizeof(*elem));
85 elem->attributeSet = 0;
86 ae[ae_num] = elem;
88 wrbuf_puts(type_str, yaz_tok_parse_string(tp));
89 t = yaz_tok_move(tp);
90 if (t == YAZ_TOK_EOF)
91 {
92 wrbuf_destroy(type_str);
93 if (set_str)
94 wrbuf_destroy(set_str);
95 break;
96 }
97 if (t == YAZ_TOK_STRING)
98 {
99 wrbuf_puts(w, " ");
101 set_str = type_str;
102
103 elem->attributeSet =
105 wrbuf_cstr(set_str), ct->nmem);
106
107 type_str = wrbuf_alloc();
108 wrbuf_puts(type_str, yaz_tok_parse_string(tp));
109 t = yaz_tok_move(tp);
110 }
111 elem->attributeType = nmem_intdup(ct->nmem, 0);
112 if (sscanf(wrbuf_cstr(type_str), ODR_INT_PRINTF, elem->attributeType)
113 != 1)
114 {
115 wrbuf_destroy(type_str);
116 if (set_str)
117 wrbuf_destroy(set_str);
118 yaz_log(YLOG_WARN, "Expected numeric attribute type");
119 ret = -1;
120 break;
121 }
122
123 wrbuf_destroy(type_str);
124 if (set_str)
125 wrbuf_destroy(set_str);
126
127 if (t != '=')
128 {
129 yaz_log(YLOG_WARN, "Expected = after after attribute type");
130 ret = -1;
131 break;
132 }
133 t = yaz_tok_move(tp);
134 if (t != YAZ_TOK_STRING) /* value */
135 {
136 yaz_log(YLOG_WARN, "Missing attribute value");
137 ret = -1;
138 break;
139 }
140 value_str = yaz_tok_parse_string(tp);
141 if (yaz_isdigit(*value_str))
142 {
144 elem->value.numeric =
145 nmem_intdup(ct->nmem, atoi(value_str));
146 }
147 else
148 {
150 nmem_malloc(ct->nmem, sizeof(*ca));
152 elem->value.complex = ca;
153 ca->num_list = 1;
154 ca->list = (Z_StringOrNumeric **)
155 nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric *));
156 ca->list[0] = (Z_StringOrNumeric *)
157 nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric));
159 ca->list[0]->u.string = nmem_strdup(ct->nmem, value_str);
160 ca->num_semanticAction = 0;
161 ca->semanticAction = 0;
162 }
163 wrbuf_puts(w, "=");
165 t = yaz_tok_move(tp);
166 wrbuf_puts(w, " ");
167 ae_num++;
168 }
169 if (ret == 0) /* OK? */
170 {
171 struct cql_prop_entry **pp = &ct->entry;
172 while (*pp)
173 pp = &(*pp)->next;
174 *pp = (struct cql_prop_entry *) xmalloc(sizeof(**pp));
175 (*pp)->pattern = xstrdup(pattern);
176 (*pp)->value = xstrdup(wrbuf_cstr(w));
177
178 (*pp)->attr_list.num_attributes = ae_num;
179 if (ae_num == 0)
180 (*pp)->attr_list.attributes = 0;
181 else
182 {
183 (*pp)->attr_list.attributes = (Z_AttributeElement **)
184 nmem_malloc(ct->nmem,
185 ae_num * sizeof(Z_AttributeElement *));
186 memcpy((*pp)->attr_list.attributes, ae,
187 ae_num * sizeof(Z_AttributeElement *));
188 }
189 (*pp)->next = 0;
190
191 if (0)
192 {
194 Z_AttributeList *alp = &(*pp)->attr_list;
196 z_AttributeList(pr, &alp, 0, 0);
197 odr_destroy(pr);
198 }
199 }
200 wrbuf_destroy(w);
201 return ret;
202}
203
205 const char *value)
206{
207 int r;
212 return r;
213}
214
216{
218 if (cql_transform_define_FILE(ct, f))
219 {
221 return 0;
222 }
223 return ct;
224}
225
227{
228 char line[1024];
229 int ret = 0;
230
232 while (ret == 0 && fgets(line, sizeof(line)-1, f))
233 {
235 int t = yaz_tok_move(tp);
236 if (t == YAZ_TOK_STRING)
237 {
238 char *pattern = xstrdup(yaz_tok_parse_string(tp)); /* copy as it's yaz_tok_move resets */
239 t = yaz_tok_move(tp);
240 if (t != '=')
241 ret = -1;
242 else
243 {
245 ret = -1;
246 }
247 xfree(pattern);
248 }
249 else if (t != YAZ_TOK_EOF)
250 {
251 ret = -1;
252 }
254 }
255 return ret;
256}
257
259{
260 struct cql_prop_entry *pe;
261 if (!ct)
262 return;
263 pe = ct->entry;
264 while (pe)
265 {
266 struct cql_prop_entry *pe_next = pe->next;
267 xfree(pe->pattern);
268 xfree(pe->value);
269 xfree(pe);
270 pe = pe_next;
271 }
274 nmem_destroy(ct->nmem);
275 xfree(ct);
276}
277
279{
281 if (cql_transform_define_fname(ct, fname))
282 {
284 return 0;
285 }
286 return ct;
287}
288
290{
291 int ret;
292 FILE *f = fopen(fname, "r");
293 if (!f)
294 return -2;
295 ret = cql_transform_define_FILE(ct, f);
296 fclose(f);
297 return ret;
298}
299
300#if 0
301struct Z_AttributeElement {
303 int *attributeType;
304 int which;
305 union {
306 int *numeric;
308#define Z_AttributeValue_numeric 1
309#define Z_AttributeValue_complex 2
310 } value;
311};
312#endif
313
315{
318 int len_a, len_b;
319 char *buf_a, *buf_b;
320 int ret;
321
322 z_AttributeElement(odr_a, &a, 0, 0);
323 z_AttributeElement(odr_b, &b, 0, 0);
324
325 buf_a = odr_getbuf(odr_a, &len_a, 0);
326 buf_b = odr_getbuf(odr_b, &len_b, 0);
327
328 ret = yaz_memcmp(buf_a, buf_b, len_a, len_b);
329
330 odr_destroy(odr_a);
331 odr_destroy(odr_b);
332 return ret;
333}
334
336 const char *category,
337 Z_AttributeList *attributes)
338{
339 struct cql_prop_entry *e;
340 size_t clen = strlen(category);
341 for (e = ct->entry; e; e = e->next)
342 {
343 if (!strncmp(e->pattern, category, clen))
344 {
345 /* category matches.. See if attributes in pattern value
346 are all listed in actual attributes */
347 int i;
348 for (i = 0; i < e->attr_list.num_attributes; i++)
349 {
350 /* entry attribute */
352 int j;
353 for (j = 0; j < attributes->num_attributes; j++)
354 {
355 /* actual attribute */
356 Z_AttributeElement a_ae = *attributes->attributes[j];
357 if (!compare_attr(e_ae, &a_ae))
358 break;
359 if (a_ae.attributeSet &&
361 a_ae.attributeSet = 0;
362 if (!compare_attr(e_ae, &a_ae))
363 break;
364 }
365 if (j == attributes->num_attributes)
366 break; /* i was not found at all.. try next pattern */
367
368 }
369 if (i == e->attr_list.num_attributes)
370 return e->pattern + clen;
371 }
372 }
373 return 0;
374}
375
377 const char *pat1, const char *pat2,
378 const char *pat3)
379{
380 char pattern[120];
381 struct cql_prop_entry *e;
382
383 if (pat1 && pat2 && pat3)
384 sprintf(pattern, "%.39s.%.39s.%.39s", pat1, pat2, pat3);
385 else if (pat1 && pat2)
386 sprintf(pattern, "%.39s.%.39s", pat1, pat2);
387 else if (pat1 && pat3)
388 sprintf(pattern, "%.39s.%.39s", pat1, pat3);
389 else if (pat1)
390 sprintf(pattern, "%.39s", pat1);
391 else
392 return 0;
393
394 for (e = ct->entry; e; e = e->next)
395 {
396 if (!cql_strcmp(e->pattern, pattern))
397 return e->value;
398 }
399 return 0;
400}
401
402int cql_pr_attr_uri(cql_transform_t ct, WRBUF addinfo, const char *category,
403 const char *uri, const char *val, const char *default_val,
404 void (*pr)(const char *buf, void *client_data),
405 void *client_data,
406 int errcode)
407{
408 const char *res = 0;
409 const char *eval = val ? val : default_val;
410 const char *prefix = 0;
411
412 if (uri)
413 {
414 struct cql_prop_entry *e;
415
416 for (e = ct->entry; e; e = e->next)
417 if (!memcmp(e->pattern, "set.", 4) && e->value &&
418 !strcmp(e->value, uri))
419 {
420 prefix = e->pattern+4;
421 break;
422 }
423 /* must have a prefix now - if not it's an error */
424 }
425
426 if (!uri || prefix)
427 {
428 if (!res)
429 res = cql_lookup_property(ct, category, prefix, eval);
430 /* we have some aliases for some relations unfortunately.. */
431 if (!res && !prefix && !strcmp(category, "relation"))
432 {
433 if (!strcmp(val, "=="))
434 res = cql_lookup_property(ct, category, prefix, "exact");
435 if (!strcmp(val, "="))
436 res = cql_lookup_property(ct, category, prefix, "eq");
437 if (!strcmp(val, "<="))
438 res = cql_lookup_property(ct, category, prefix, "le");
439 if (!strcmp(val, ">="))
440 res = cql_lookup_property(ct, category, prefix, "ge");
441 }
442 if (!res)
443 res = cql_lookup_property(ct, category, prefix, "*");
444 }
445 if (res)
446 {
447 char buf[64];
448
449 const char *cp0 = res, *cp1;
450 while ((cp1 = strchr(cp0, '=')))
451 {
452 int i;
453 while (*cp1 && *cp1 != ' ')
454 cp1++;
455 if (cp1 - cp0 >= (ptrdiff_t) sizeof(buf))
456 break;
457 memcpy(buf, cp0, cp1 - cp0);
458 buf[cp1-cp0] = 0;
459 (*pr)("@attr ", client_data);
460
461 for (i = 0; buf[i]; i++)
462 {
463 if (buf[i] == '*')
464 (*pr)(eval, client_data);
465 else
466 {
467 char tmp[2];
468 tmp[0] = buf[i];
469 tmp[1] = '\0';
470 (*pr)(tmp, client_data);
471 }
472 }
473 (*pr)(" ", client_data);
474 cp0 = cp1;
475 while (*cp0 == ' ')
476 cp0++;
477 }
478 return 0;
479 }
480 /* error ... */
481 if (errcode == 0)
482 return 1; /* signal error, but do not set addinfo */
483 if (val)
484 wrbuf_puts(addinfo, val);
485 return errcode;
486}
487
488int cql_pr_attr(cql_transform_t ct, WRBUF addinfo, const char *category,
489 const char *val, const char *default_val,
490 void (*pr)(const char *buf, void *client_data),
491 void *client_data,
492 int errcode)
493{
494 return cql_pr_attr_uri(ct, addinfo, category, 0 /* uri */,
495 val, default_val, pr, client_data, errcode);
496}
497
498
499static void cql_pr_int(int val,
500 void (*pr)(const char *buf, void *client_data),
501 void *client_data)
502{
503 char buf[21]; /* enough characters to 2^64 */
504 sprintf(buf, "%d", val);
505 (*pr)(buf, client_data);
506 (*pr)(" ", client_data);
507}
508
509
510static int cql_pr_prox(cql_transform_t ct, struct cql_node *mods,
511 WRBUF addinfo,
512 void (*pr)(const char *buf, void *client_data),
513 void *client_data)
514{
515 int exclusion = 0;
516 int distance = -1;
517 int ordered = 0;
518 int proxrel = 2; /* less than or equal */
519 int unit = 2; /* word */
520
521 while (mods)
522 {
523 const char *name = mods->u.st.index;
524 const char *term = mods->u.st.term;
525 const char *relation = mods->u.st.relation;
526
527 if (!strcmp(name, "distance")) {
528 distance = strtol(term, (char**) 0, 0);
529 if (!strcmp(relation, "="))
530 proxrel = 3;
531 else if (!strcmp(relation, ">"))
532 proxrel = 5;
533 else if (!strcmp(relation, "<"))
534 proxrel = 1;
535 else if (!strcmp(relation, ">="))
536 proxrel = 4;
537 else if (!strcmp(relation, "<="))
538 proxrel = 2;
539 else if (!strcmp(relation, "<>"))
540 proxrel = 6;
541 else
542 {
543 wrbuf_puts(addinfo, relation);
545 }
546 }
547 else if (!strcmp(name, "ordered"))
548 ordered = 1;
549 else if (!strcmp(name, "unordered"))
550 ordered = 0;
551 else if (!strcmp(name, "unit"))
552 {
553 unit = z_str_to_ProxUnit(term);
554 if (unit == 0)
555 {
556 wrbuf_puts(addinfo, term);
558 }
559 }
560 else
561 {
562 wrbuf_puts(addinfo, name);
564 }
565 mods = mods->u.st.modifiers;
566 }
567
568 if (distance == -1)
569 distance = (unit == 2) ? 1 : 0;
570
571 cql_pr_int(exclusion, pr, client_data);
572 cql_pr_int(distance, pr, client_data);
573 cql_pr_int(ordered, pr, client_data);
574 cql_pr_int(proxrel, pr, client_data);
575 (*pr)("k ", client_data);
576 cql_pr_int(unit, pr, client_data);
577
578 return 0;
579}
580
581/* ### checks for CQL relation-name rather than Type-1 attribute */
582static int has_modifier(struct cql_node *cn, const char *name) {
583 struct cql_node *mod;
584 for (mod = cn->u.st.modifiers; mod != 0; mod = mod->u.st.modifiers) {
585 if (!mod->u.st.term && !strcmp(mod->u.st.index, name))
586 return 1;
587 }
588
589 return 0;
590}
591
593 struct cql_node *cn, WRBUF addinfo,
594 const char *term, int length,
595 void (*pr)(const char *buf, void *client_data),
596 void *client_data)
597{
598 int i, r;
599 const char *ns = cn->u.st.index_uri;
600 int z3958_mode = 0;
601 int process_term = 1;
602
603
604 if (has_modifier(cn, "regexp"))
605 process_term = 0;
606 else if (has_modifier(cn, "unmasked"))
607 process_term = 0;
608 else if (cql_lookup_property(ct, "truncation", 0, "cql"))
609 {
610 process_term = 0;
611 r = cql_pr_attr(ct, addinfo, "truncation", "cql", 0,
612 pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
613 if (r)
614 return r;
615 }
616 assert(cn->which == CQL_NODE_ST);
617
618 if (process_term)
619 { /* convert term via truncation.things */
620 unsigned anchor = 0;
621 unsigned trunc = 0;
622 for (i = 0; i < length; i++)
623 {
624 if (term[i] == '\\' && i < length - 1)
625 i++;
626 else
627 {
628 switch (term[i])
629 {
630 case '^':
631 if (i == 0)
632 anchor |= 1;
633 else if (i == length - 1)
634 anchor |= 2;
635 break;
636 case '*':
637 if (i == 0)
638 trunc |= 1;
639 else if (i == length - 1)
640 trunc |= 2;
641 else
642 z3958_mode = 1;
643 break;
644 case '?':
645 z3958_mode = 1;
646 break;
647 }
648 }
649 }
650 if (anchor == 3)
651 {
652 r = cql_pr_attr(ct, addinfo, "position", "firstAndLast", 0,
653 pr, client_data,
655 if (r)
656 return r;
657 term++;
658 length -= 2;
659 }
660 else if (anchor == 1)
661 {
662 r = cql_pr_attr(ct, addinfo, "position", "first", 0,
663 pr, client_data,
665 if (r)
666 return r;
667 term++;
668 length--;
669 }
670 else if (anchor == 2)
671 {
672 r = cql_pr_attr(ct, addinfo, "position", "last", 0,
673 pr, client_data,
675 if (r)
676 return r;
677 length--;
678 }
679 else
680 {
681 r = cql_pr_attr(ct, addinfo, "position", "any", 0,
682 pr, client_data,
684 if (r)
685 return r;
686 }
687 if (z3958_mode == 0)
688 {
689 if (trunc == 3 && !cql_pr_attr(ct, addinfo, "truncation",
690 "both", 0, pr, client_data, 0))
691 {
692 term++;
693 length -= 2;
694 }
695 else if (trunc == 1 && !cql_pr_attr(ct, addinfo, "truncation",
696 "left", 0, pr, client_data, 0))
697 {
698 term++;
699 length--;
700 }
701 else if (trunc == 2 && !cql_pr_attr(ct, addinfo, "truncation",
702 "right", 0, pr, client_data, 0))
703 {
704 length--;
705 }
706 else if (trunc)
707 z3958_mode = 1;
708 else
709 cql_pr_attr(ct, addinfo, "truncation", "none", 0,
710 pr, client_data, 0);
711 }
712 if (z3958_mode)
713 {
714 r = cql_pr_attr(ct, addinfo, "truncation", "z3958", 0,
715 pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
716 if (r)
717 return r;
718 }
719 }
720 if (ns)
721 {
722 r = cql_pr_attr_uri(ct, addinfo, "index", ns,
723 cn->u.st.index, "serverChoice",
724 pr, client_data, YAZ_SRW_UNSUPP_INDEX);
725 if (r)
726 return r;
727 }
728 if (cn->u.st.modifiers)
729 {
730 struct cql_node *mod = cn->u.st.modifiers;
731 for (; mod; mod = mod->u.st.modifiers)
732 {
733 if (!mod->u.st.term)
734 {
735 r = cql_pr_attr(ct, addinfo,
736 "relationModifier", mod->u.st.index, 0,
737 pr, client_data,
739 if (r)
740 return r;
741 }
742 }
743 }
744 (*pr)("\"", client_data);
745 if (process_term)
746 for (i = 0; i < length; i++)
747 {
748 char x[2]; /* temp buffer */
749 if (term[i] == '\\' && i < length - 1)
750 {
751 i++;
752 if (strchr("\"\\", term[i]))
753 pr("\\", client_data);
754 if (z3958_mode && strchr("#?", term[i]))
755 pr("\\\\", client_data); /* double \\ to survive PQF parse */
756 x[0] = term[i];
757 x[1] = '\0';
758 pr(x, client_data);
759 }
760 else if (z3958_mode && term[i] == '*')
761 {
762 pr("?", client_data);
763 if (i < length - 1 && yaz_isdigit(term[i+1]))
764 pr("\\\\", client_data); /* dbl \\ to survive PQF parse */
765 }
766 else if (z3958_mode && term[i] == '?')
767 {
768 pr("#", client_data);
769 }
770 else
771 {
772 if (term[i] == '\"')
773 pr("\\", client_data);
774 if (z3958_mode && strchr("#?", term[i]))
775 pr("\\\\", client_data); /* dbl \\ to survive PQF parse */
776 x[0] = term[i];
777 x[1] = '\0';
778 pr(x, client_data);
779 }
780 }
781 else
782 {
783 for (i = 0; i < length; i++)
784 {
785 char x[2];
786 x[0] = term[i];
787 x[1] = '\0';
788 pr(x, client_data);
789 }
790 }
791 (*pr)("\" ", client_data);
792 return 0;
793}
794
795static int emit_terms(cql_transform_t ct, struct cql_node *cn,
796 WRBUF addinfo,
797 void (*pr)(const char *buf, void *client_data),
798 void *client_data,
799 const char *op)
800{
801 struct cql_node *ne = cn->u.st.extra_terms;
802 int r;
803 if (ne)
804 {
805 (*pr)("@", client_data);
806 (*pr)(op, client_data);
807 (*pr)(" ", client_data);
808 }
809 r = emit_term(ct, cn, addinfo, cn->u.st.term, strlen(cn->u.st.term),
810 pr, client_data);
811 for (; !r && ne; ne = ne->u.st.extra_terms)
812 {
813 if (ne->u.st.extra_terms)
814 {
815 (*pr)("@", client_data);
816 (*pr)(op, client_data);
817 (*pr)(" ", client_data);
818 }
819 r = emit_term(ct, cn, addinfo, ne->u.st.term, strlen(ne->u.st.term),
820 pr, client_data);
821 }
822 return r;
823}
824
825static int emit_wordlist(cql_transform_t ct, struct cql_node *cn,
826 WRBUF addinfo,
827 void (*pr)(const char *buf, void *client_data),
828 void *client_data,
829 const char *op)
830{
831 int r = 0;
832 const char *cp0 = cn->u.st.term;
833 const char *cp1;
834 const char *last_term = 0;
835 int last_length = 0;
836 while (!r && cp0)
837 {
838 while (*cp0 == ' ')
839 cp0++;
840 cp1 = strchr(cp0, ' ');
841 if (last_term)
842 {
843 (*pr)("@", client_data);
844 (*pr)(op, client_data);
845 (*pr)(" ", client_data);
846 r = emit_term(ct, cn, addinfo, last_term, last_length,
847 pr, client_data);
848 }
849 last_term = cp0;
850 if (cp1)
851 last_length = cp1 - cp0;
852 else
853 last_length = strlen(cp0);
854 cp0 = cp1;
855 }
856 if (!r && last_term)
857 r = emit_term(ct, cn, addinfo, last_term, last_length, pr, client_data);
858 return r;
859}
860
861static int emit_node(cql_transform_t ct, struct cql_node *cn,
862 WRBUF addinfo,
863 void (*pr)(const char *buf, void *client_data),
864 void *client_data)
865{
866 const char *ns;
867 int r = 0;
868 struct cql_node *mods;
869
870 if (!cn)
871 return 0;
872 switch (cn->which)
873 {
874 case CQL_NODE_ST:
875 ns = cn->u.st.index_uri;
876 if (ns)
877 {
878 if (!strcmp(ns, cql_uri())
879 && cn->u.st.index && !cql_strcmp(cn->u.st.index, "resultSet"))
880 {
881 (*pr)("@set \"", client_data);
882 (*pr)(cn->u.st.term, client_data);
883 (*pr)("\" ", client_data);
884 return 0;
885 }
886 }
887 else
888 {
890 }
891 if (cn->u.st.modifiers)
892 {
893 struct cql_node *mod = cn->u.st.modifiers;
894 for (; mod; mod = mod->u.st.modifiers)
895 {
896 if (mod->u.st.term) /* only modifiers with name+value */
897 {
898 /* only relation = supported at the moment */
899 if (mod->u.st.relation && strcmp(mod->u.st.relation, "="))
900 {
901 wrbuf_puts(addinfo, mod->u.st.relation);
903 }
904 pr("@prox 0 0 0 0 k 8 ", client_data);
905 }
906 }
907 }
908 cql_pr_attr(ct, addinfo, "always", 0, 0, pr, client_data, 0);
909 r = cql_pr_attr(ct, addinfo, "relation", cn->u.st.relation, 0,
910 pr, client_data, YAZ_SRW_UNSUPP_RELATION);
911 if (r)
912 return r;
913 r = cql_pr_attr(ct, addinfo, "structure", cn->u.st.relation, 0,
914 pr, client_data,
916 if (r)
917 return r;
918 if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "all"))
919 r = emit_wordlist(ct, cn, addinfo, pr, client_data, "and");
920 else if (cn->u.st.relation && !cql_strcmp(cn->u.st.relation, "any"))
921 r = emit_wordlist(ct, cn, addinfo, pr, client_data, "or");
922 else
923 r = emit_terms(ct, cn, addinfo, pr, client_data, "and");
924
925 if (cn->u.st.modifiers)
926 {
927 struct cql_node *mod = cn->u.st.modifiers;
928 for (; mod; mod = mod->u.st.modifiers)
929 {
930 if (mod->u.st.term)
931 {
932 r = cql_pr_attr_uri(ct, addinfo, "index",
933 mod->u.st.index_uri,
934 mod->u.st.index, "serverChoice",
935 pr, client_data, YAZ_SRW_UNSUPP_INDEX);
936 if (r)
937 return r;
938 pr(mod->u.st.term, client_data);
939 pr(" ", client_data);
940 }
941 }
942 }
943 break;
944 case CQL_NODE_BOOL:
945 (*pr)("@", client_data);
946 (*pr)(cn->u.boolean.value, client_data);
947 (*pr)(" ", client_data);
948 mods = cn->u.boolean.modifiers;
949 if (!strcmp(cn->u.boolean.value, "prox"))
950 {
951 r = cql_pr_prox(ct, mods, addinfo, pr, client_data);
952 if (r)
953 return r;
954 }
955 else if (mods)
956 {
957 /* Boolean modifiers other than on proximity not supported */
958 wrbuf_puts(addinfo, mods->u.st.index);
960 }
961
962 r = emit_node(ct, cn->u.boolean.left, addinfo, pr, client_data);
963 if (r)
964 return r;
965 r = emit_node(ct, cn->u.boolean.right, addinfo, pr, client_data);
966 if (r)
967 return r;
968 break;
969 case CQL_NODE_SORT:
970 r = emit_node(ct, cn->u.sort.search, addinfo, pr, client_data);
971 break;
972 default:
973 fprintf(stderr, "Fatal: impossible CQL node-type %d\n", cn->which);
974 abort();
975 }
976 return r;
977}
978
980 WRBUF addinfo,
981 void (*pr)(const char *buf, void *client_data),
982 void *client_data)
983{
984 struct cql_prop_entry *e;
985 NMEM nmem = nmem_create();
986 int r;
987
988 for (e = ct->entry; e ; e = e->next)
989 {
990 if (!cql_strncmp(e->pattern, "set.", 4))
991 cql_apply_prefix(nmem, cn, e->pattern+4, e->value);
992 else if (!cql_strcmp(e->pattern, "set"))
993 cql_apply_prefix(nmem, cn, 0, e->value);
994 }
995 r = emit_node(ct, cn, addinfo, pr, client_data);
996 nmem_destroy(nmem);
997 return r;
998}
999
1001 void (*pr)(const char *buf, void *client_data),
1002 void *client_data)
1003{
1004 WRBUF addinfo = wrbuf_alloc();
1005 int r = cql_transform_r(ct, cn, addinfo, pr, client_data);
1006 cql_transform_set_error(ct, r, wrbuf_cstr(addinfo));
1007 wrbuf_destroy(addinfo);
1008 return r;
1009}
1010
1011int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f)
1012{
1013 return cql_transform(ct, cn, cql_fputs, f);
1014}
1015
1017 char *out, int max)
1018{
1019 struct cql_buf_write_info info;
1020 int r;
1021
1022 info.off = 0;
1023 info.max = max;
1024 info.buf = out;
1025 r = cql_transform(ct, cn, cql_buf_write_handler, &info);
1026 if (info.off < 0) {
1027 /* Attempt to write past end of buffer. For some reason, this
1028 SRW diagnostic is deprecated, but it's so perfect for our
1029 purposes that it would be stupid not to use it. */
1030 char numbuf[30];
1031 sprintf(numbuf, "%ld", (long) info.max);
1033 return -1;
1034 }
1035 if (info.off >= 0)
1036 info.buf[info.off] = '\0';
1037 return r;
1038}
1039
1040int cql_transform_error(cql_transform_t ct, const char **addinfo)
1041{
1042 *addinfo = wrbuf_len(ct->addinfo) ? wrbuf_cstr(ct->addinfo) : 0;
1043 return ct->error;
1044}
1045
1046void cql_transform_set_error(cql_transform_t ct, int error, const char *addinfo)
1047{
1048 wrbuf_rewind(ct->addinfo);
1049 if (addinfo)
1050 wrbuf_puts(ct->addinfo, addinfo);
1051 ct->error = error;
1052}
1053
1054/*
1055 * Local variables:
1056 * c-basic-offset: 4
1057 * c-file-style: "Stroustrup"
1058 * indent-tabs-mode: nil
1059 * End:
1060 * vim: shiftwidth=4 tabstop=8 expandtab
1061 */
#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
nmem_int_t * nmem_intdup(NMEM mem, nmem_int_t v)
allocates and sets integer for NMEM
Definition nmemsdup.c:41
char * nmem_strdup(NMEM mem, const char *src)
allocates string on NMEM handle (similar strdup)
Definition nmemsdup.c:18
void odr_setprint_noclose(ODR o, FILE *file)
Definition odr.c:169
char * odr_getbuf(ODR o, int *len, int *size)
Definition odr.c:277
ODR odr_createmem(int direction)
Definition odr.c:200
void odr_destroy(ODR o)
Definition odr.c:253
#define ODR_INT_PRINTF
Definition odr.h:49
#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.
union Z_AttributeElement::@50 value
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
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::@72 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::@10::@12 boolean
struct cql_node * right
Definition cql.h:147
char * value
Definition cql.h:143
struct cql_node::@10::@13 sort
struct cql_node * search
Definition cql.h:159
struct cql_node::@10::@11 st
struct cql_node * extra_terms
Definition cql.h:138
union cql_node::@10 u
struct cql_node * modifiers
Definition cql.h:136
int which
Definition cql.h:121
char * relation
Definition cql.h:132
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
Definition odr.h:125
string buffer
Definition wrbuf.h:43
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.
#define YAZ_TOK_EOF
Definition tokenizer.h:38
#define YAZ_TOK_STRING
Definition tokenizer.h:40
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
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