YAZ  4.2.57
solrtransform.c
Go to the documentation of this file.
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <assert.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <yaz/rpn2solr.h>
17 #include <yaz/xmalloc.h>
18 #include <yaz/diagsrw.h>
19 #include <yaz/tokenizer.h>
20 #include <yaz/wrbuf.h>
21 #include <yaz/z-core.h>
22 #include <yaz/matchstr.h>
23 #include <yaz/oid_db.h>
24 #include <yaz/log.h>
25 #include <yaz/cql.h>
26 
28  char *pattern;
29  char *value;
32 };
33 
37  int error;
38  char *addinfo;
41 };
42 
43 
44 /* TODO Utility functions, split out into separate file */
45 int solr_strcmp(const char *s1, const char *s2) {
46  return cql_strcmp(s1, s2);
47 }
48 
49 int solr_strncmp(const char *s1, const char *s2, size_t n) {
50  return cql_strncmp(s1, s2, n);
51 }
52 
53 /* TODO FIX */
54 const char *solr_uri(void)
55 {
56  return "TODO:SOLR URI";
57 }
58 
59 void solr_buf_write_handler (const char *b, void *client_data)
60 {
61  struct solr_buf_write_info *info = (struct solr_buf_write_info *)client_data;
62  int l = strlen(b);
63  if (info->off < 0 || (info->off + l >= info->max))
64  {
65  info->off = -1;
66  return;
67  }
68  memcpy (info->buf + info->off, b, l);
69  info->off += l;
70 }
71 
72 
73 /* Utility functions end */
74 
76 {
77  solr_transform_t ct = (solr_transform_t) xmalloc(sizeof(*ct));
79  ct->w = wrbuf_alloc();
80  ct->error = 0;
81  ct->addinfo = 0;
82  ct->entry = 0;
83  ct->nmem = nmem_create();
84  return ct;
85 }
86 
88  const char *pattern,
89  yaz_tok_parse_t tp)
90 {
91  int ae_num = 0;
92  Z_AttributeElement *ae[20];
93  int ret = 0; /* 0=OK, != 0 FAIL */
94  int t;
95  t = yaz_tok_move(tp);
96 
97  while (t == YAZ_TOK_STRING && ae_num < 20)
98  {
99  WRBUF type_str = wrbuf_alloc();
100  WRBUF set_str = 0;
101  Z_AttributeElement *elem = 0;
102  const char *value_str = 0;
103  /* attset type=value OR type=value */
104 
105  elem = (Z_AttributeElement *) nmem_malloc(ct->nmem, sizeof(*elem));
106  elem->attributeSet = 0;
107  ae[ae_num] = elem;
109  wrbuf_puts(type_str, yaz_tok_parse_string(tp));
110  t = yaz_tok_move(tp);
111  if (t == YAZ_TOK_EOF)
112  {
113  wrbuf_destroy(type_str);
114  if (set_str)
115  wrbuf_destroy(set_str);
116  break;
117  }
118  if (t == YAZ_TOK_STRING)
119  {
120  wrbuf_puts(ct->w, " ");
122  set_str = type_str;
123 
124  elem->attributeSet =
126  wrbuf_cstr(set_str), ct->nmem);
127 
128  type_str = wrbuf_alloc();
129  wrbuf_puts(type_str, yaz_tok_parse_string(tp));
130  t = yaz_tok_move(tp);
131  }
132  elem->attributeType = nmem_intdup(ct->nmem, 0);
133  if (sscanf(wrbuf_cstr(type_str), ODR_INT_PRINTF, elem->attributeType)
134  != 1)
135  {
136  wrbuf_destroy(type_str);
137  if (set_str)
138  wrbuf_destroy(set_str);
139  yaz_log(YLOG_WARN, "Expected numeric attribute type");
140  ret = -1;
141  break;
142  }
143 
144  wrbuf_destroy(type_str);
145  if (set_str)
146  wrbuf_destroy(set_str);
147 
148  if (t != '=')
149  {
150  yaz_log(YLOG_WARN, "Expected = after after attribute type");
151  ret = -1;
152  break;
153  }
154  t = yaz_tok_move(tp);
155  if (t != YAZ_TOK_STRING) /* value */
156  {
157  yaz_log(YLOG_WARN, "Missing attribute value");
158  ret = -1;
159  break;
160  }
161  value_str = yaz_tok_parse_string(tp);
162  if (yaz_isdigit(*value_str))
163  {
165  elem->value.numeric =
166  nmem_intdup(ct->nmem, atoi(value_str));
167  }
168  else
169  {
171  nmem_malloc(ct->nmem, sizeof(*ca));
173  elem->value.complex = ca;
174  ca->num_list = 1;
175  ca->list = (Z_StringOrNumeric **)
176  nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric *));
177  ca->list[0] = (Z_StringOrNumeric *)
178  nmem_malloc(ct->nmem, sizeof(Z_StringOrNumeric));
180  ca->list[0]->u.string = nmem_strdup(ct->nmem, value_str);
181  ca->num_semanticAction = 0;
182  ca->semanticAction = 0;
183  }
184  wrbuf_puts(ct->w, "=");
186  t = yaz_tok_move(tp);
187  wrbuf_puts(ct->w, " ");
188  ae_num++;
189  }
190  if (ret == 0) /* OK? */
191  {
192  struct solr_prop_entry **pp = &ct->entry;
193  while (*pp)
194  pp = &(*pp)->next;
195  *pp = (struct solr_prop_entry *) xmalloc(sizeof(**pp));
196  (*pp)->pattern = xstrdup(pattern);
197  (*pp)->value = xstrdup(wrbuf_cstr(ct->w));
198 
199  (*pp)->attr_list.num_attributes = ae_num;
200  if (ae_num == 0)
201  (*pp)->attr_list.attributes = 0;
202  else
203  {
204  (*pp)->attr_list.attributes = (Z_AttributeElement **)
205  nmem_malloc(ct->nmem,
206  ae_num * sizeof(Z_AttributeElement *));
207  memcpy((*pp)->attr_list.attributes, ae,
208  ae_num * sizeof(Z_AttributeElement *));
209  }
210  (*pp)->next = 0;
211 
212  if (0)
213  {
215  Z_AttributeList *alp = &(*pp)->attr_list;
216  odr_setprint(pr, yaz_log_file());
217  z_AttributeList(pr, &alp, 0, 0);
218  odr_setprint(pr, 0);
219  odr_destroy(pr);
220  }
221  }
222  return ret;
223 }
224 
226  const char *value)
227 {
228  int r;
229  yaz_tok_parse_t tp = yaz_tok_parse_buf(ct->tok_cfg, value);
231  r = solr_transform_parse_tok_line(ct, pattern, tp);
233  return r;
234 }
235 
237 {
239  char line[1024];
240 
242 
243  while (fgets(line, sizeof(line)-1, f))
244  {
245  yaz_tok_parse_t tp = yaz_tok_parse_buf(ct->tok_cfg, line);
246  int t;
247  wrbuf_rewind(ct->w);
248  t = yaz_tok_move(tp);
249  if (t == YAZ_TOK_STRING)
250  {
251  char * pattern = xstrdup(yaz_tok_parse_string(tp));
252  t = yaz_tok_move(tp);
253  if (t != '=')
254  {
257  return 0;
258  }
259  if (solr_transform_parse_tok_line(ct, pattern, tp))
260  {
263  return 0;
264  }
265  xfree(pattern);
266  }
267  else if (t != YAZ_TOK_EOF)
268  {
271  return 0;
272  }
274  }
275  return ct;
276 }
277 
279 {
280  struct solr_prop_entry *pe;
281  if (!ct)
282  return;
283  pe = ct->entry;
284  while (pe)
285  {
286  struct solr_prop_entry *pe_next = pe->next;
287  xfree(pe->pattern);
288  xfree(pe->value);
289  xfree(pe);
290  pe = pe_next;
291  }
292  xfree(ct->addinfo);
294  wrbuf_destroy(ct->w);
295  nmem_destroy(ct->nmem);
296  xfree(ct);
297 }
298 
300 {
301  solr_transform_t ct;
302  FILE *f = fopen(fname, "r");
303  if (!f)
304  return 0;
305  ct = solr_transform_open_FILE(f);
306  fclose(f);
307  return ct;
308 }
309 
310 #if 0
311 struct Z_AttributeElement {
312  Z_AttributeSetId *attributeSet; /* OPT */
313  int *attributeType;
314  int which;
315  union {
316  int *numeric;
318 #define Z_AttributeValue_numeric 1
319 #define Z_AttributeValue_complex 2
320  } value;
321 };
322 #endif
323 
325 {
326  ODR odr_a = odr_createmem(ODR_ENCODE);
327  ODR odr_b = odr_createmem(ODR_ENCODE);
328  int len_a, len_b;
329  char *buf_a, *buf_b;
330  int ret;
331 
332  z_AttributeElement(odr_a, &a, 0, 0);
333  z_AttributeElement(odr_b, &b, 0, 0);
334 
335  buf_a = odr_getbuf(odr_a, &len_a, 0);
336  buf_b = odr_getbuf(odr_b, &len_b, 0);
337 
338  ret = yaz_memcmp(buf_a, buf_b, len_a, len_b);
339 
340  odr_destroy(odr_a);
341  odr_destroy(odr_b);
342  return ret;
343 }
344 
346  const char *category,
347  Z_AttributeList *attributes)
348 {
349  struct solr_prop_entry *e;
350  size_t clen = strlen(category);
351  for (e = ct->entry; e; e = e->next)
352  {
353  if (!strncmp(e->pattern, category, clen))
354  {
355  /* category matches.. See if attributes in pattern value
356  are all listed in actual attributes */
357  int i;
358  for (i = 0; i < e->attr_list.num_attributes; i++)
359  {
360  /* entry attribute */
362  int j;
363  for (j = 0; j < attributes->num_attributes; j++)
364  {
365  /* actual attribute */
366  Z_AttributeElement *a_ae = attributes->attributes[j];
367  int r = compare_attr(e_ae, a_ae);
368  if (r == 0)
369  break;
370  }
371  if (j == attributes->num_attributes)
372  break; /* i was not found at all.. try next pattern */
373 
374  }
375  if (i == e->attr_list.num_attributes)
376  return e->pattern + clen;
377  }
378  }
379  return 0;
380 }
381 
383  const char *pat1, const char *pat2,
384  const char *pat3)
385 {
386  char pattern[120];
387  struct solr_prop_entry *e;
388 
389  if (pat1 && pat2 && pat3)
390  sprintf(pattern, "%.39s.%.39s.%.39s", pat1, pat2, pat3);
391  else if (pat1 && pat2)
392  sprintf(pattern, "%.39s.%.39s", pat1, pat2);
393  else if (pat1 && pat3)
394  sprintf(pattern, "%.39s.%.39s", pat1, pat3);
395  else if (pat1)
396  sprintf(pattern, "%.39s", pat1);
397  else
398  return 0;
399 
400  for (e = ct->entry; e; e = e->next)
401  {
402  if (!solr_strcmp(e->pattern, pattern))
403  return e->value;
404  }
405  return 0;
406 }
407 
408 int solr_pr_attr_uri(solr_transform_t ct, const char *category,
409  const char *uri, const char *val, const char *default_val,
410  void (*pr)(const char *buf, void *client_data),
411  void *client_data,
412  int errcode)
413 {
414  const char *res = 0;
415  const char *eval = val ? val : default_val;
416  const char *prefix = 0;
417 
418  if (uri)
419  {
420  struct solr_prop_entry *e;
421 
422  for (e = ct->entry; e; e = e->next)
423  if (!memcmp(e->pattern, "set.", 4) && e->value &&
424  !strcmp(e->value, uri))
425  {
426  prefix = e->pattern+4;
427  break;
428  }
429  /* must have a prefix now - if not it's an error */
430  }
431 
432  if (!uri || prefix)
433  {
434  if (!res)
435  res = solr_lookup_property(ct, category, prefix, eval);
436  /* we have some aliases for some relations unfortunately.. */
437  if (!res && !prefix && !strcmp(category, "relation"))
438  {
439  if (!strcmp(val, "=="))
440  res = solr_lookup_property(ct, category, prefix, "exact");
441  if (!strcmp(val, "="))
442  res = solr_lookup_property(ct, category, prefix, "eq");
443  if (!strcmp(val, "<="))
444  res = solr_lookup_property(ct, category, prefix, "le");
445  if (!strcmp(val, ">="))
446  res = solr_lookup_property(ct, category, prefix, "ge");
447  }
448  if (!res)
449  res = solr_lookup_property(ct, category, prefix, "*");
450  }
451  if (res)
452  {
453  char buf[64];
454 
455  const char *cp0 = res, *cp1;
456  while ((cp1 = strchr(cp0, '=')))
457  {
458  int i;
459  while (*cp1 && *cp1 != ' ')
460  cp1++;
461  if (cp1 - cp0 >= (ptrdiff_t) sizeof(buf))
462  break;
463  memcpy(buf, cp0, cp1 - cp0);
464  buf[cp1-cp0] = 0;
465  (*pr)("@attr ", client_data);
466 
467  for (i = 0; buf[i]; i++)
468  {
469  if (buf[i] == '*')
470  (*pr)(eval, client_data);
471  else
472  {
473  char tmp[2];
474  tmp[0] = buf[i];
475  tmp[1] = '\0';
476  (*pr)(tmp, client_data);
477  }
478  }
479  (*pr)(" ", client_data);
480  cp0 = cp1;
481  while (*cp0 == ' ')
482  cp0++;
483  }
484  return 1;
485  }
486  /* error ... */
487  if (errcode && !ct->error)
488  {
489  ct->error = errcode;
490  if (val)
491  ct->addinfo = xstrdup(val);
492  else
493  ct->addinfo = 0;
494  }
495  return 0;
496 }
497 
498 int solr_pr_attr(solr_transform_t ct, const char *category,
499  const char *val, const char *default_val,
500  void (*pr)(const char *buf, void *client_data),
501  void *client_data,
502  int errcode)
503 {
504  return solr_pr_attr_uri(ct, category, 0 /* uri */,
505  val, default_val, pr, client_data, errcode);
506 }
507 
508 
509 static void solr_pr_int(int val,
510  void (*pr)(const char *buf, void *client_data),
511  void *client_data)
512 {
513  char buf[21]; /* enough characters to 2^64 */
514  sprintf(buf, "%d", val);
515  (*pr)(buf, client_data);
516  (*pr)(" ", client_data);
517 }
518 
519 
520 static int solr_pr_prox(solr_transform_t ct, struct solr_node *mods,
521  void (*pr)(const char *buf, void *client_data),
522  void *client_data)
523 {
524  int exclusion = 0;
525  int distance = -1;
526  int ordered = 0;
527  int proxrel = 2; /* less than or equal */
528  int unit = 2; /* word */
529 
530  while (mods)
531  {
532  const char *name = mods->u.st.index;
533  const char *term = mods->u.st.term;
534  const char *relation = mods->u.st.relation;
535 
536  if (!strcmp(name, "distance")) {
537  distance = strtol(term, (char**) 0, 0);
538  if (!strcmp(relation, "="))
539  proxrel = 3;
540  else if (!strcmp(relation, ">"))
541  proxrel = 5;
542  else if (!strcmp(relation, "<"))
543  proxrel = 1;
544  else if (!strcmp(relation, ">="))
545  proxrel = 4;
546  else if (!strcmp(relation, "<="))
547  proxrel = 2;
548  else if (!strcmp(relation, "<>"))
549  proxrel = 6;
550  else
551  {
553  ct->addinfo = xstrdup(relation);
554  return 0;
555  }
556  }
557  else if (!strcmp(name, "ordered"))
558  ordered = 1;
559  else if (!strcmp(name, "unordered"))
560  ordered = 0;
561  else if (!strcmp(name, "unit"))
562  {
563  if (!strcmp(term, "word"))
564  unit = 2;
565  else if (!strcmp(term, "sentence"))
566  unit = 3;
567  else if (!strcmp(term, "paragraph"))
568  unit = 4;
569  else if (!strcmp(term, "element"))
570  unit = 8;
571  else
572  {
574  ct->addinfo = xstrdup(term);
575  return 0;
576  }
577  }
578  else
579  {
581  ct->addinfo = xstrdup(name);
582  return 0;
583  }
584  mods = mods->u.st.modifiers;
585  }
586 
587  if (distance == -1)
588  distance = (unit == 2) ? 1 : 0;
589 
590  solr_pr_int(exclusion, pr, client_data);
591  solr_pr_int(distance, pr, client_data);
592  solr_pr_int(ordered, pr, client_data);
593  solr_pr_int(proxrel, pr, client_data);
594  (*pr)("k ", client_data);
595  solr_pr_int(unit, pr, client_data);
596 
597  return 1;
598 }
599 
600 /* Returns location of first wildcard character in the `length'
601  * characters starting at `term', or a null pointer of there are
602  * none -- like memchr().
603  */
604 static const char *wcchar(int start, const char *term, int length)
605 {
606  while (length > 0)
607  {
608  if (start || term[-1] != '\\')
609  if (strchr("*?", *term))
610  return term;
611  term++;
612  length--;
613  start = 0;
614  }
615  return 0;
616 }
617 
618 
619 /* ### checks for SOLR relation-name rather than Type-1 attribute */
620 static int has_modifier(struct solr_node *cn, const char *name) {
621  struct solr_node *mod;
622  for (mod = cn->u.st.modifiers; mod != 0; mod = mod->u.st.modifiers) {
623  if (!strcmp(mod->u.st.index, name))
624  return 1;
625  }
626 
627  return 0;
628 }
629 
630 
632  struct solr_node *cn,
633  const char *term, int length,
634  void (*pr)(const char *buf, void *client_data),
635  void *client_data)
636 {
637  int i;
638  const char *ns = cn->u.st.index_uri;
639  int process_term = !has_modifier(cn, "regexp");
640  char *z3958_mem = 0;
641 
642  assert(cn->which == SOLR_NODE_ST);
643 
644  if (process_term && length > 0)
645  {
646  if (length > 1 && term[0] == '^' && term[length-1] == '^')
647  {
648  solr_pr_attr(ct, "position", "firstAndLast", 0,
650  term++;
651  length -= 2;
652  }
653  else if (term[0] == '^')
654  {
655  solr_pr_attr(ct, "position", "first", 0,
657  term++;
658  length--;
659  }
660  else if (term[length-1] == '^')
661  {
662  solr_pr_attr(ct, "position", "last", 0,
664  length--;
665  }
666  else
667  {
668  solr_pr_attr(ct, "position", "any", 0,
670  }
671  }
672 
673  if (process_term && length > 0)
674  {
675  const char *first_wc = wcchar(1, term, length);
676  const char *second_wc = first_wc ?
677  wcchar(0, first_wc+1, length-(first_wc-term)-1) : 0;
678 
679  /* Check for well-known globbing patterns that represent
680  * simple truncation attributes as expected by, for example,
681  * Bath-compliant server. If we find such a pattern but
682  * there's no mapping for it, that's fine: we just use a
683  * general pattern-matching attribute.
684  */
685  if (first_wc == term && second_wc == term + length-1
686  && *first_wc == '*' && *second_wc == '*'
687  && solr_pr_attr(ct, "truncation", "both", 0, pr, client_data, 0))
688  {
689  term++;
690  length -= 2;
691  }
692  else if (first_wc == term && second_wc == 0 && *first_wc == '*'
693  && solr_pr_attr(ct, "truncation", "left", 0,
694  pr, client_data, 0))
695  {
696  term++;
697  length--;
698  }
699  else if (first_wc == term + length-1 && second_wc == 0
700  && *first_wc == '*'
701  && solr_pr_attr(ct, "truncation", "right", 0,
702  pr, client_data, 0))
703  {
704  length--;
705  }
706  else if (first_wc)
707  {
708  /* We have one or more wildcard characters, but not in a
709  * way that can be dealt with using only the standard
710  * left-, right- and both-truncation attributes. We need
711  * to translate the pattern into a Z39.58-type pattern,
712  * which has been supported in BIB-1 since 1996. If
713  * there's no configuration element for "truncation.z3958"
714  * we indicate this as error 28 "Masking character not
715  * supported".
716  */
717  int i;
718  solr_pr_attr(ct, "truncation", "z3958", 0,
719  pr, client_data, YAZ_SRW_MASKING_CHAR_UNSUPP);
720  z3958_mem = (char *) xmalloc(length+1);
721  for (i = 0; i < length; i++)
722  {
723  if (i > 0 && term[i-1] == '\\')
724  z3958_mem[i] = term[i];
725  else if (term[i] == '*')
726  z3958_mem[i] = '?';
727  else if (term[i] == '?')
728  z3958_mem[i] = '#';
729  else
730  z3958_mem[i] = term[i];
731  }
732  z3958_mem[length] = '\0';
733  term = z3958_mem;
734  }
735  else {
736  /* No masking characters. Use "truncation.none" if given. */
737  solr_pr_attr(ct, "truncation", "none", 0,
738  pr, client_data, 0);
739  }
740  }
741  if (ns) {
742  solr_pr_attr_uri(ct, "index", ns,
743  cn->u.st.index, "serverChoice",
744  pr, client_data, YAZ_SRW_UNSUPP_INDEX);
745  }
746  if (cn->u.st.modifiers)
747  {
748  struct solr_node *mod = cn->u.st.modifiers;
749  for (; mod; mod = mod->u.st.modifiers)
750  {
751  solr_pr_attr(ct, "relationModifier", mod->u.st.index, 0,
752  pr, client_data, YAZ_SRW_UNSUPP_RELATION_MODIFIER);
753  }
754  }
755 
756  (*pr)("\"", client_data);
757  for (i = 0; i<length; i++)
758  {
759  /* pr(int) each character */
760  /* we do not need to deal with \-sequences because the
761  SOLR and PQF terms have same \-format, bug #1988 */
762  char buf[2];
763 
764  buf[0] = term[i];
765  buf[1] = '\0';
766  (*pr)(buf, client_data);
767  }
768  (*pr)("\" ", client_data);
769  xfree(z3958_mem);
770 }
771 
773  struct solr_node *cn,
774  void (*pr)(const char *buf, void *client_data),
775  void *client_data,
776  const char *op)
777 {
778  struct solr_node *ne = cn->u.st.extra_terms;
779  if (ne)
780  {
781  (*pr)("@", client_data);
782  (*pr)(op, client_data);
783  (*pr)(" ", client_data);
784  }
785  emit_term(ct, cn, cn->u.st.term, strlen(cn->u.st.term),
786  pr, client_data);
787  for (; ne; ne = ne->u.st.extra_terms)
788  {
789  if (ne->u.st.extra_terms)
790  {
791  (*pr)("@", client_data);
792  (*pr)(op, client_data);
793  (*pr)(" ", client_data);
794  }
795  emit_term(ct, cn, ne->u.st.term, strlen(ne->u.st.term),
796  pr, client_data);
797  }
798 }
799 
801  struct solr_node *cn,
802  void (*pr)(const char *buf, void *client_data),
803  void *client_data,
804  const char *op)
805 {
806  const char *cp0 = cn->u.st.term;
807  const char *cp1;
808  const char *last_term = 0;
809  int last_length = 0;
810  while(cp0)
811  {
812  while (*cp0 == ' ')
813  cp0++;
814  cp1 = strchr(cp0, ' ');
815  if (last_term)
816  {
817  (*pr)("@", client_data);
818  (*pr)(op, client_data);
819  (*pr)(" ", client_data);
820  emit_term(ct, cn, last_term, last_length, pr, client_data);
821  }
822  last_term = cp0;
823  if (cp1)
824  last_length = cp1 - cp0;
825  else
826  last_length = strlen(cp0);
827  cp0 = cp1;
828  }
829  if (last_term)
830  emit_term(ct, cn, last_term, last_length, pr, client_data);
831 }
832 
834  struct solr_node *cn,
835  void (*pr)(const char *buf, void *client_data),
836  void *client_data)
837 {
838  const char *ns;
839  struct solr_node *mods;
840 
841  if (!cn)
842  return;
843  switch (cn->which)
844  {
845  case SOLR_NODE_ST:
846  ns = cn->u.st.index_uri;
847  if (ns)
848  {
849  /* TODO If relevant fix with solr_uri */
850  if (!strcmp(ns, solr_uri())
851  && cn->u.st.index && !solr_strcmp(cn->u.st.index, "resultSet"))
852  {
853  (*pr)("@set \"", client_data);
854  (*pr)(cn->u.st.term, client_data);
855  (*pr)("\" ", client_data);
856  return ;
857  }
858  }
859  else
860  {
861  if (!ct->error)
862  {
864  ct->addinfo = 0;
865  }
866  }
867  solr_pr_attr(ct, "always", 0, 0, pr, client_data, 0);
868  solr_pr_attr(ct, "relation", cn->u.st.relation, 0, pr, client_data,
870  solr_pr_attr(ct, "structure", cn->u.st.relation, 0,
872  if (cn->u.st.relation && !solr_strcmp(cn->u.st.relation, "all"))
873  emit_wordlist(ct, cn, pr, client_data, "and");
874  else if (cn->u.st.relation && !solr_strcmp(cn->u.st.relation, "any"))
875  emit_wordlist(ct, cn, pr, client_data, "or");
876  else
877  emit_terms(ct, cn, pr, client_data, "and");
878  break;
879  case SOLR_NODE_BOOL:
880  (*pr)("@", client_data);
881  (*pr)(cn->u.boolean.value, client_data);
882  (*pr)(" ", client_data);
883  mods = cn->u.boolean.modifiers;
884  if (!strcmp(cn->u.boolean.value, "prox"))
885  {
886  if (!solr_pr_prox(ct, mods, pr, client_data))
887  return;
888  }
889  else if (mods)
890  {
891  /* Boolean modifiers other than on proximity not supported */
893  ct->addinfo = xstrdup(mods->u.st.index);
894  return;
895  }
896 
897  solr_transform_r(ct, cn->u.boolean.left, pr, client_data);
898  solr_transform_r(ct, cn->u.boolean.right, pr, client_data);
899  break;
900 
901  default:
902  fprintf(stderr, "Fatal: impossible SOLR node-type %d\n", cn->which);
903  abort();
904  }
905 }
906 
908  void (*pr)(const char *buf, void *client_data),
909  void *client_data)
910 {
911  struct solr_prop_entry *e;
912  NMEM nmem = nmem_create();
913 
914  ct->error = 0;
915  xfree(ct->addinfo);
916  ct->addinfo = 0;
917 
918  for (e = ct->entry; e ; e = e->next)
919  {
920  /* TODO remove as SOLR dont supports sets.
921  if (!solr_strncmp(e->pattern, "set.", 4))
922  solr_apply_prefix(nmem, cn, e->pattern+4, e->value);
923  else if (!solr_strcmp(e->pattern, "set"))
924  solr_apply_prefix(nmem, cn, 0, e->value);
925  */
926  }
927  solr_transform_r(ct, cn, pr, client_data);
928  nmem_destroy(nmem);
929  return ct->error;
930 }
931 
932 
933 int solr_transform_FILE(solr_transform_t ct, struct solr_node *cn, FILE *f)
934 {
935  /* We can use the cql_fputs util */
936  return solr_transform(ct, cn, cql_fputs, f);
937 }
938 
939 int solr_transform_buf(solr_transform_t ct, struct solr_node *cn, char *out, int max)
940 {
941  struct solr_buf_write_info info;
942  int r;
943 
944  info.off = 0;
945  info.max = max;
946  info.buf = out;
947  r = solr_transform(ct, cn, cql_buf_write_handler, &info);
948  if (info.off < 0) {
949  /* Attempt to write past end of buffer. For some reason, this
950  SRW diagnostic is deprecated, but it's so perfect for our
951  purposes that it would be stupid not to use it. */
952  char numbuf[30];
954  sprintf(numbuf, "%ld", (long) info.max);
955  ct->addinfo = xstrdup(numbuf);
956  return -1;
957  }
958  if (info.off >= 0)
959  info.buf[info.off] = '\0';
960  return r;
961 }
962 
963 int solr_transform_error(solr_transform_t ct, const char **addinfo)
964 {
965  *addinfo = ct->addinfo;
966  return ct->error;
967 }
968 
969 void solr_transform_set_error(solr_transform_t ct, int error, const char *addinfo)
970 {
971  xfree(ct->addinfo);
972  ct->addinfo = addinfo ? xstrdup(addinfo) : 0;
973  ct->error = error;
974 }
975 
976 /*
977  * Local variables:
978  * c-basic-offset: 4
979  * c-file-style: "Stroustrup"
980  * indent-tabs-mode: nil
981  * End:
982  * vim: shiftwidth=4 tabstop=8 expandtab
983  */
984