1 /* $Id: cqltransform.c,v 1.1 2003-10-27 12:21:30 adam Exp $
2 Copyright (C) 2002-2003
5 This file is part of the YAZ toolkit.
14 struct cql_prop_entry {
17 struct cql_prop_entry *next;
20 struct cql_transform_t_ {
21 struct cql_prop_entry *entry;
26 cql_transform_t cql_transform_open_FILE(FILE *f)
29 cql_transform_t ct = (cql_transform_t) malloc (sizeof(*ct));
30 struct cql_prop_entry **pp = &ct->entry;
34 while (fgets(line, sizeof(line)-1, f))
36 const char *cp_value_start;
37 const char *cp_value_end;
38 const char *cp_pattern_end;
39 const char *cp = line;
40 while (*cp && !strchr(" \t=\r\n#", *cp))
45 while (*cp && strchr(" \t\r\n", *cp))
50 while (*cp && strchr(" \t\r\n", *cp))
53 if (!(cp_value_end = strchr(cp, '#')))
54 cp_value_end = strlen(line) + line;
56 if (cp_value_end != cp_value_start &&
57 strchr(" \t\r\n", cp_value_end[-1]))
59 *pp = (struct cql_prop_entry *) malloc (sizeof(**pp));
60 (*pp)->pattern = (char *) malloc (cp_pattern_end - line + 1);
61 memcpy ((*pp)->pattern, line, cp_pattern_end - line);
62 (*pp)->pattern[cp_pattern_end-line] = 0;
64 (*pp)->value = (char *) malloc (cp_value_end - cp_value_start + 1);
65 if (cp_value_start != cp_value_end)
66 memcpy ((*pp)->value, cp_value_start, cp_value_end-cp_value_start);
67 (*pp)->value[cp_value_end - cp_value_start] = 0;
74 void cql_transform_close(cql_transform_t ct)
76 struct cql_prop_entry *pe;
82 struct cql_prop_entry *pe_next = pe->next;
93 cql_transform_t cql_transform_open_fname(const char *fname)
96 FILE *f = fopen(fname, "r");
99 ct = cql_transform_open_FILE(f);
104 static const char *cql_lookup_property(cql_transform_t ct,
105 const char *pat1, const char *pat2)
108 struct cql_prop_entry *e;
111 sprintf (pattern, "%.39s%.39s", pat1, pat2);
113 sprintf (pattern, "%.39s", pat1);
114 for (e = ct->entry; e; e = e->next)
116 if (!strcmp(e->pattern, pattern))
122 static const char *cql_lookup_value(cql_transform_t ct,
126 struct cql_prop_entry *e;
127 int len = strlen(prefix);
129 for (e = ct->entry; e; e = e->next)
131 if (!memcmp(e->pattern, prefix, len) && !strcmp(e->value, value))
132 return e->pattern + len;
138 int cql_pr_attr(cql_transform_t ct, const char *category,
140 const char *default_val,
141 void (*pr)(const char *buf, void *client_data),
146 res = cql_lookup_property(ct, category, val ? val : default_val);
148 res = cql_lookup_property(ct, category, "*");
153 const char *cp0 = res, *cp1;
154 while ((cp1 = strchr(cp0, '=')))
156 while (*cp1 && *cp1 != ' ')
158 if (cp1 - cp0 >= sizeof(buf))
160 memcpy (buf, cp0, cp1 - cp0);
162 (*pr)("@attr ", client_data);
163 (*pr)(buf, client_data);
164 (*pr)(" ", client_data);
172 if (errcode && !ct->error)
175 ct->addinfo = strdup(val);
180 void emit_term(cql_transform_t ct,
181 const char *term, int length,
182 void (*pr)(const char *buf, void *client_data),
188 if (length > 1 && term[0] == '^' && term[length-1] == '^')
190 cql_pr_attr(ct, "position.", "firstAndLast", 0,
191 pr, client_data, 32);
195 else if (term[0] == '^')
197 cql_pr_attr(ct, "position.", "first", 0,
198 pr, client_data, 32);
201 else if (term[length-1] == '^')
203 cql_pr_attr(ct, "position.", "last", 0,
204 pr, client_data, 32);
209 cql_pr_attr(ct, "position.", "any", 0,
210 pr, client_data, 32);
213 (*pr)("\"", client_data);
214 for (i = 0; i<length; i++)
219 (*pr)(buf, client_data);
221 (*pr)("\" ", client_data);
224 void emit_wordlist(cql_transform_t ct,
226 void (*pr)(const char *buf, void *client_data),
230 const char *cp0 = cn->u.st.term;
232 const char *last_term = 0;
238 cp1 = strchr(cp0, ' ');
241 (*pr)("@", client_data);
242 (*pr)(op, client_data);
243 (*pr)(" ", client_data);
244 emit_term(ct, last_term, last_length, pr, client_data);
248 last_length = cp1 - cp0;
250 last_length = strlen(cp0);
254 emit_term(ct, last_term, last_length, pr, client_data);
258 static const char *cql_get_ns(cql_transform_t ct,
260 struct cql_node **prefix_ar, int prefix_level,
261 const char **n_prefix,
262 const char **n_suffix)
267 const char *cp = cn->u.st.index;
268 const char *cp_dot = strchr(cp, '.');
270 /* strz current prefix (empty if not given) */
271 if (cp_dot && cp_dot-cp < sizeof(prefix))
273 memcpy (prefix, cp, cp_dot - cp);
274 prefix[cp_dot - cp] = 0;
279 /* 2. lookup in prefix_ar. and return NS */
280 for (i = prefix_level; !ns && --i >= 0; )
282 struct cql_node *cn_prefix = prefix_ar[i];
283 for (; cn_prefix; cn_prefix = cn_prefix->u.mod.next)
285 if (*prefix && cn_prefix->u.mod.name &&
286 !strcmp(prefix, cn_prefix->u.mod.name))
288 ns = cn_prefix->u.mod.value;
291 else if (!*prefix && !cn_prefix->u.mod.name)
293 ns = cn_prefix->u.mod.value;
303 ct->addinfo = strdup(prefix);
307 /* 3. lookup in set.NS for new prefix */
308 *n_prefix = cql_lookup_value(ct, "set.", ns);
314 ct->addinfo = strdup(ns);
318 /* 4. lookup qualifier.prefix. */
321 cp_dot = strchr(cp, '.');
323 *n_suffix = cp_dot ? cp_dot+1 : cp;
327 void cql_transform_r(cql_transform_t ct,
329 void (*pr)(const char *buf, void *client_data),
331 struct cql_node **prefix_ar, int prefix_level)
333 const char *ns, *n_prefix, *n_suffix;
340 if (cn->u.st.prefixes && prefix_level < 20)
341 prefix_ar[prefix_level++] = cn->u.st.prefixes;
342 ns = cql_get_ns(ct, cn, prefix_ar, prefix_level, &n_prefix, &n_suffix);
346 sprintf (n_full, "%.20s.%.40s", n_prefix, n_suffix);
348 if (!strcmp(ns, "http://www.loc.gov/zing/cql/srw-indexes/v1.0/")
349 && !strcmp(n_suffix, "resultSet"))
351 (*pr)("@set \"", client_data);
352 (*pr)(cn->u.st.term, client_data);
353 (*pr)("\" ", client_data);
356 cql_pr_attr(ct, "qualifier.", n_full, "srw.serverChoice",
357 pr, client_data, 16);
360 if (cn->u.st.relation && !strcmp(cn->u.st.relation, "="))
361 cql_pr_attr(ct, "relation.", "eq", "scr",
362 pr, client_data, 19);
363 else if (cn->u.st.relation && !strcmp(cn->u.st.relation, "<="))
364 cql_pr_attr(ct, "relation.", "le", "scr",
365 pr, client_data, 19);
366 else if (cn->u.st.relation && !strcmp(cn->u.st.relation, ">="))
367 cql_pr_attr(ct, "relation.", "ge", "scr",
368 pr, client_data, 19);
370 cql_pr_attr(ct, "relation.", cn->u.st.relation, "eq",
371 pr, client_data, 19);
372 if (cn->u.st.modifiers)
374 struct cql_node *mod = cn->u.st.modifiers;
375 for (; mod; mod = mod->u.mod.next)
377 cql_pr_attr(ct, "relationModifier.", mod->u.mod.value, 0,
378 pr, client_data, 20);
381 cql_pr_attr(ct, "structure.", cn->u.st.relation, 0,
382 pr, client_data, 24);
383 if (cn->u.st.relation && !strcmp(cn->u.st.relation, "all"))
385 emit_wordlist(ct, cn, pr, client_data, "and");
387 else if (cn->u.st.relation && !strcmp(cn->u.st.relation, "any"))
389 emit_wordlist(ct, cn, pr, client_data, "or");
393 emit_term(ct, cn->u.st.term, strlen(cn->u.st.term),
398 if (cn->u.boolean.prefixes && prefix_level < 20)
399 prefix_ar[prefix_level++] = cn->u.boolean.prefixes;
400 (*pr)("@", client_data);
401 (*pr)(cn->u.boolean.value, client_data);
402 (*pr)(" ", client_data);
404 cql_transform_r(ct, cn->u.boolean.left, pr, client_data,
405 prefix_ar, prefix_level);
406 cql_transform_r(ct, cn->u.boolean.right, pr, client_data,
407 prefix_ar, prefix_level);
411 int cql_transform(cql_transform_t ct,
413 void (*pr)(const char *buf, void *client_data),
416 struct cql_node *prefix_ar[20], **pp;
417 struct cql_prop_entry *e;
426 for (e = ct->entry; e ; e = e->next)
428 if (!memcmp(e->pattern, "set.", 4))
430 *pp = cql_node_mk_mod(e->pattern+4, e->value);
431 pp = &(*pp)->u.mod.next;
433 else if (!strcmp(e->pattern, "set"))
435 *pp = cql_node_mk_mod(0, e->value);
436 pp = &(*pp)->u.mod.next;
439 cql_transform_r (ct, cn, pr, client_data, prefix_ar, 1);
440 cql_node_destroy(prefix_ar[0]);
445 int cql_transform_FILE(cql_transform_t ct, struct cql_node *cn, FILE *f)
447 return cql_transform(ct, cn, cql_fputs, f);
450 int cql_transform_buf(cql_transform_t ct, struct cql_node *cn,
453 struct cql_buf_write_info info;
459 r = cql_transform(ct, cn, cql_buf_write_handler, &info);
461 info.buf[info.off] = '\0';
465 int cql_transform_error(cql_transform_t ct, const char **addinfo)
467 *addinfo = ct->addinfo;