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