YAZ  5.34.0
cql2ccl.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  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 
17 #include <yaz/cql.h>
18 
19 static int cql_to_ccl_r(struct cql_node *cn,
20  void (*pr)(const char *buf, void *client_data),
21  void *client_data);
22 
23 static void pr_term(const char **cpp, int stop_at_space,
24  void (*pr)(const char *buf, void *client_data),
25  void *client_data)
26 {
27  const char *cp;
28  int quote_mode = 0;
29  for (cp = *cpp; *cp; cp++)
30  {
31  char x[4];
32 
33  if (*cp == '\\' && cp[1])
34  {
35  if (!quote_mode)
36  {
37  pr("\"", client_data);
38  quote_mode = 1;
39  }
40  cp++;
41  if (*cp == '\"' || *cp == '\\')
42  pr("\\", client_data);
43  x[0] = *cp;
44  x[1] = '\0';
45  pr(x, client_data);
46  }
47  else if (*cp == '*')
48  {
49  if (quote_mode)
50  {
51  pr("\"", client_data);
52  quote_mode = 0;
53  }
54  pr("?", client_data);
55  }
56  else if (*cp == '?')
57  {
58  if (quote_mode)
59  {
60  pr("\"", client_data);
61  quote_mode = 0;
62  }
63  pr("#", client_data);
64  }
65  else if (*cp == ' ' && stop_at_space)
66  break;
67  else
68  {
69  if (!quote_mode)
70  {
71  pr("\"", client_data);
72  quote_mode = 1;
73  }
74  x[0] = *cp;
75  x[1] = '\0';
76  pr(x, client_data);
77  }
78  }
79  if (quote_mode)
80  pr("\"", client_data);
81  if (cp == *cpp)
82  pr("\"\"", client_data);
83  *cpp = cp;
84 }
85 
86 static int node(struct cql_node *cn,
87  void (*pr)(const char *buf, void *client_data),
88  void *client_data)
89 {
90  const char *ccl_field = 0;
91  const char *split_op = 0;
92  const char *ccl_rel = 0;
93  const char *rel = cn->u.st.relation;
94 
95  if (cn->u.st.index && cql_strcmp(cn->u.st.index,
96  "cql.serverChoice"))
97  ccl_field = cn->u.st.index;
98 
99  if (!rel)
100  ;
101  else if (!strcmp(rel, "<") || !strcmp(rel, "<=")
102  || !strcmp(rel, ">") || !strcmp(rel, ">=")
103  || !strcmp(rel, "<>") || !strcmp(rel, "="))
104  ccl_rel = rel;
105  else if (!cql_strcmp(rel, "all"))
106  {
107  ccl_rel = "=";
108  split_op = "and";
109  }
110  else if (!cql_strcmp(rel, "any"))
111  {
112  ccl_rel = "=";
113  split_op = "or";
114  }
115  else if (!strcmp(rel, "==") || !cql_strcmp(rel, "adj"))
116  {
117  ccl_rel = "=";
118  }
119  else
120  {
121  /* unsupported relation */
122  return -1;
123  }
124  for (; cn; cn = cn->u.st.extra_terms)
125  {
126  const char *cp = cn->u.st.term;
127  while (1)
128  {
129  if (ccl_field && ccl_rel)
130  {
131  pr(ccl_field, client_data);
132  pr(ccl_rel, client_data);
133  if (!split_op)
134  ccl_rel = 0;
135  }
136  pr_term(&cp, split_op ? 1 : 0, pr, client_data);
137  while (*cp == ' ')
138  cp++;
139  if (*cp == '\0')
140  break;
141  pr(" ", client_data);
142  if (split_op)
143  {
144  pr(split_op, client_data);
145  pr(" ", client_data);
146  }
147  }
148  if (cn->u.st.extra_terms)
149  {
150  pr(" ", client_data);
151  if (split_op)
152  {
153  pr(split_op, client_data);
154  pr(" ", client_data);
155  }
156  }
157  }
158  return 0;
159 }
160 
161 
162 static int bool(struct cql_node *cn,
163  void (*pr)(const char *buf, void *client_data),
164  void *client_data)
165 {
166  char *value = cn->u.boolean.value;
167  int r;
168 
169  pr("(", client_data);
170  r = cql_to_ccl_r(cn->u.boolean.left, pr, client_data);
171  if (r)
172  return r;
173 
174  pr(") ", client_data);
175 
176  if (cql_strcmp(value, "prox"))
177  { /* not proximity. assuming boolean */
178  pr(value, client_data);
179  }
180  else
181  {
182  struct cql_node *n = cn->u.boolean.modifiers;
183  int ordered = 0;
184  int distance = 1;
185  for (; n ; n = n->u.st.modifiers)
186  if (n->which == CQL_NODE_ST)
187  {
188  if (!cql_strcmp(n->u.st.index, "unit"))
189  {
190  if (!cql_strcmp(n->u.st.term, "word"))
191  ;
192  else
193  return -1;
194  }
195  else if (!cql_strcmp(n->u.st.index, "distance"))
196  {
197  if (!strcmp(n->u.st.relation, "<="))
198  distance = atoi(n->u.st.term);
199  else if (!strcmp(n->u.st.relation, "<"))
200  distance = atoi(n->u.st.term) - 1;
201  else
202  return -1;
203  }
204  else if (!cql_strcmp(n->u.st.index, "unordered"))
205  {
206  ordered = 0;
207  }
208  else if (!cql_strcmp(n->u.st.index, "ordered"))
209  {
210  ordered = 1;
211  }
212  else
213  return -1;
214  }
215  pr(ordered ? "!" : "%", client_data);
216  if (distance != 1)
217  {
218  char x[40];
219  sprintf(x, "%d", distance);
220  pr(x, client_data);
221  }
222  }
223  pr(" (", client_data);
224 
225  r = cql_to_ccl_r(cn->u.boolean.right, pr, client_data);
226  pr(")", client_data);
227  return r;
228 }
229 
230 static int cql_to_ccl_r(struct cql_node *cn,
231  void (*pr)(const char *buf, void *client_data),
232  void *client_data)
233 {
234  if (!cn)
235  return -1;
236 
237  switch (cn->which)
238  {
239  case CQL_NODE_ST:
240  return node(cn, pr, client_data);
241  case CQL_NODE_BOOL:
242  return bool(cn, pr, client_data);
243  case CQL_NODE_SORT:
244  return cql_to_ccl_r(cn->u.sort.search, pr, client_data);
245  }
246  return -1;
247 }
248 
249 int cql_to_ccl(struct cql_node *cn,
250  void (*pr)(const char *buf, void *client_data),
251  void *client_data)
252 {
253  return cql_to_ccl_r(cn, pr, client_data);
254 }
255 
256 void cql_to_ccl_stdio(struct cql_node *cn, FILE *f)
257 {
258  cql_to_ccl(cn, cql_fputs, f);
259 }
260 
261 int cql_to_ccl_buf(struct cql_node *cn, char *out, int max)
262 {
263  struct cql_buf_write_info info;
264  int r;
265  info.off = 0;
266  info.max = max;
267  info.buf = out;
268  r = cql_to_ccl(cn, cql_buf_write_handler, &info);
269  if (info.off >= 0)
270  info.buf[info.off] = '\0';
271  else
272  return -2; /* buffer overflow */
273  return r;
274 }
275 
276 /*
277  * Local variables:
278  * c-basic-offset: 4
279  * c-file-style: "Stroustrup"
280  * indent-tabs-mode: nil
281  * End:
282  * vim: shiftwidth=4 tabstop=8 expandtab
283  */
284 
static void pr_term(const char **cpp, int stop_at_space, void(*pr)(const char *buf, void *client_data), void *client_data)
Definition: cql2ccl.c:23
static int bool(struct cql_node *cn, void(*pr)(const char *buf, void *client_data), void *client_data)
Definition: cql2ccl.c:162
int cql_to_ccl(struct cql_node *cn, void(*pr)(const char *buf, void *client_data), void *client_data)
converts CQL tree to CCL and writes to user-defined stream
Definition: cql2ccl.c:249
static int node(struct cql_node *cn, void(*pr)(const char *buf, void *client_data), void *client_data)
Definition: cql2ccl.c:86
static int cql_to_ccl_r(struct cql_node *cn, void(*pr)(const char *buf, void *client_data), void *client_data)
Definition: cql2ccl.c:230
int cql_to_ccl_buf(struct cql_node *cn, char *out, int max)
converts CQL tree to CCL and writes result to buffer
Definition: cql2ccl.c:261
void cql_to_ccl_stdio(struct cql_node *cn, FILE *f)
converts CQL tree to CCL and writes to file
Definition: cql2ccl.c:256
Header with public definitions about CQL.
#define CQL_NODE_SORT
Node type: sortby single spec.
Definition: cql.h:115
#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_strcmp(const char *s1, const char *s2)
compares two CQL strings (ala strcmp)
Definition: cqlutil.c:194
void cql_fputs(const char *buf, void *client_data)
stream handle for file (used by cql_to_xml_stdio)
Definition: cqlutil.c:18
Structure used by cql_buf_write_handler.
Definition: cql.h:170
char * buf
Definition: cql.h:173
CQL parse tree (node)
Definition: cql.h:119
struct cql_node::@10::@12 boolean
struct cql_node::@10::@13 sort
struct cql_node::@10::@11 st
union cql_node::@10 u
int which
Definition: cql.h:121
void cql_buf_write_handler(const char *b, void *client_data)
Handler for cql_buf_write_info.
Definition: xcqlutil.c:251