de6116cf1126cd4150e9e3c403c627656440ecf6
[yaz-moved-to-github.git] / src / xcqlutil.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2013 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file xcqlutil.c
7  * \brief Implements CQL to XCQL conversion.
8  */
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 void pr_n(const char *buf,
20                 void (*pr)(const char *buf, void *client_data),
21                 void *client_data, int n)
22 {
23     int i;
24     for (i = 0; i<n; i++)
25         (*pr)(" ", client_data);
26     (*pr)(buf, client_data);
27 }
28
29 static void pr_cdata(const char *buf,
30                      void (*pr)(const char *buf, void *client_data),
31                      void *client_data)
32 {
33     const char *src = buf;
34     char bf[2];
35     while (*src)
36     {
37         switch(*src)
38         {
39         case '&':
40             (*pr)("&amp;", client_data);
41             break;
42         case '<':
43             (*pr)("&lt;", client_data);
44             break;
45         case '>':
46             (*pr)("&gt;", client_data);
47             break;
48         default:
49             bf[0] = *src;
50             bf[1] = 0;
51             (*pr)(bf, client_data);
52         }
53         src++;
54     }
55 }
56
57 static void prefixes(struct cql_node *cn,
58                      void (*pr)(const char *buf, void *client_data),
59                      void *client_data, int level)
60 {
61     int head = 0;
62     if (cn->u.st.index_uri)
63     {
64         pr_n("<prefixes>\n", pr, client_data, level);
65         head = 1;
66
67         pr_n("<prefix>\n", pr, client_data, level+2);
68         pr_n("<identifier>", pr, client_data, level+4);
69         pr_cdata(cn->u.st.index_uri, pr, client_data);
70         pr_n("</identifier>\n", pr, client_data, 0);
71         pr_n("</prefix>\n", pr, client_data, level+2);
72     }
73     if (cn->u.st.relation_uri && cn->u.st.relation)
74     {
75         if (!head)
76             pr_n("<prefixes>\n", pr, client_data, level);
77         pr_n("<prefix>\n", pr, client_data, level+2);
78         pr_n("<name>", pr, client_data, level+4);
79         pr_cdata("rel", pr, client_data);
80         pr_n("</name>\n", pr, client_data, 0);
81         pr_n("<identifier>", pr, client_data, level+4);
82         pr_cdata(cn->u.st.relation_uri, pr, client_data);
83         pr_n("</identifier>\n", pr, client_data, 0);
84         pr_n("</prefix>\n", pr, client_data, level+2);
85     }
86     if (head)
87         pr_n("</prefixes>\n", pr, client_data, level);
88 }
89
90 static void cql_to_xml_mod(struct cql_node *m,
91                            void (*pr)(const char *buf, void *client_data),
92                            void *client_data, int level)
93 {
94     if (m)
95     {
96         pr_n("<modifiers>\n", pr, client_data, level);
97         for (; m; m = m->u.st.modifiers)
98         {
99             pr_n("<modifier>\n", pr, client_data, level+2);
100             pr_n("<type>", pr, client_data, level+4);
101             pr_cdata(m->u.st.index, pr, client_data);
102             pr_n("</type>\n", pr, client_data, 0);
103             if (m->u.st.relation)
104             {
105                 pr_n("<comparison>", pr, client_data, level+4);
106                 pr_cdata(m->u.st.relation, pr, client_data);
107                 pr_n("</comparison>\n", pr, client_data, 0);
108             }
109             if (m->u.st.term)
110             {
111                 pr_n("<value>", pr, client_data, level+4);
112                 pr_cdata(m->u.st.term, pr, client_data);
113                 pr_n("</value>\n", pr, client_data, 0);
114             }
115             pr_n("</modifier>\n", pr, client_data, level+2);
116         }
117         pr_n("</modifiers>\n", pr, client_data, level);
118     }
119 }
120
121 static void cql_sort_to_xml(struct cql_node *cn,
122                          void (*pr)(const char *buf, void *client_data),
123                             void *client_data, int level)
124 {
125     if (cn)
126     {
127         pr_n("<sortKeys>\n", pr, client_data, level);
128         for (; cn; cn = cn->u.sort.next)
129         {
130             pr_n("<key>\n", pr, client_data, level+2);
131
132             if (cn->u.sort.index)
133             {
134                 pr_n("<index>", pr, client_data, level+4);
135                 pr_cdata(cn->u.sort.index, pr, client_data);
136                 pr_n("</index>\n", pr, client_data, 0);
137
138                 cql_to_xml_mod(cn->u.sort.modifiers,
139                                pr, client_data, level+6);
140             }
141             pr_n("</key>\n", pr, client_data, level+2);
142         }
143         pr_n("</sortKeys>\n", pr, client_data, level);
144     }
145 }
146
147 static void cql_to_xml_r(struct cql_node *cn,
148                          void (*pr)(const char *buf, void *client_data),
149                          void *client_data, int level,
150                          struct cql_node *sort_node)
151 {
152     if (!cn)
153         return;
154     switch (cn->which)
155     {
156     case CQL_NODE_ST:
157         pr_n("<searchClause>\n", pr, client_data, level);
158         prefixes(cn, pr, client_data, level+2);
159         if (cn->u.st.index)
160         {
161             pr_n("<index>", pr, client_data, level+2);
162             pr_cdata(cn->u.st.index, pr, client_data);
163             pr_n("</index>\n", pr, client_data, 0);
164         }
165         if (cn->u.st.relation)
166         {
167             pr_n("<relation>\n", pr, client_data, level+2);
168             pr_n("<value>", pr, client_data, level+4);
169             if (cn->u.st.relation_uri)
170                 pr_cdata("rel.", pr, client_data);
171             pr_cdata(cn->u.st.relation, pr, client_data);
172             pr_n("</value>\n", pr, client_data, 0);
173
174             if (cn->u.st.relation_uri)
175             {
176                 pr_n("<identifier>", pr, client_data, level+4);
177                 pr_cdata(cn->u.st.relation_uri, pr, client_data);
178                 pr_n("</identifier>\n", pr, client_data, 0);
179             }
180             cql_to_xml_mod(cn->u.st.modifiers,
181                            pr, client_data, level+4);
182
183             pr_n("</relation>\n", pr, client_data, level+2);
184         }
185         if (cn->u.st.term)
186         {
187             pr_n("<term>", pr, client_data, level+2);
188             pr_cdata(cn->u.st.term, pr, client_data);
189             pr_n("</term>\n", pr, client_data, 0);
190         }
191         cql_sort_to_xml(sort_node, pr, client_data, level+2);
192         pr_n("</searchClause>\n", pr, client_data, level);
193         break;
194     case CQL_NODE_BOOL:
195         pr_n("<triple>\n", pr, client_data, level);
196         if (cn->u.boolean.value)
197         {
198             pr_n("<boolean>\n", pr, client_data, level+2);
199
200             pr_n("<value>", pr, client_data, level+4);
201             pr_cdata(cn->u.boolean.value, pr, client_data);
202             pr_n("</value>\n", pr, client_data, 0);
203
204             cql_to_xml_mod(cn->u.boolean.modifiers,
205                            pr, client_data, level+4);
206
207             pr_n("</boolean>\n", pr, client_data, level+2);
208         }
209         if (cn->u.boolean.left)
210         {
211             printf ("%*s<leftOperand>\n", level+2, "");
212             cql_to_xml_r(cn->u.boolean.left, pr, client_data, level+4, 0);
213             printf ("%*s</leftOperand>\n", level+2, "");
214         }
215         if (cn->u.boolean.right)
216         {
217             printf ("%*s<rightOperand>\n", level+2, "");
218             cql_to_xml_r(cn->u.boolean.right, pr, client_data, level+4, 0);
219             printf ("%*s</rightOperand>\n", level+2, "");
220         }
221         cql_sort_to_xml(sort_node, pr, client_data, level+2);
222         pr_n("</triple>\n", pr, client_data, level);
223         break;
224     case CQL_NODE_SORT:
225         cql_to_xml_r(cn->u.sort.search, pr, client_data, level, cn);
226     }
227 }
228
229 void cql_to_xml(struct cql_node *cn,
230                 void (*pr)(const char *buf, void *client_data),
231                 void *client_data)
232 {
233     cql_to_xml_r(cn, pr, client_data, 0, 0);
234 }
235
236 void cql_to_xml_stdio(struct cql_node *cn, FILE *f)
237 {
238     cql_to_xml(cn, cql_fputs, f);
239 }
240
241 void cql_buf_write_handler (const char *b, void *client_data)
242 {
243     struct cql_buf_write_info *info = (struct cql_buf_write_info *)client_data;
244     int l = strlen(b);
245     if (info->off < 0 || (info->off + l >= info->max))
246     {
247         info->off = -1;
248         return;
249     }
250     memcpy (info->buf + info->off, b, l);
251     info->off += l;
252 }
253
254 int cql_to_xml_buf(struct cql_node *cn, char *out, int max)
255 {
256     struct cql_buf_write_info info;
257     info.off = 0;
258     info.max = max;
259     info.buf = out;
260     cql_to_xml(cn, cql_buf_write_handler, &info);
261     if (info.off >= 0)
262         info.buf[info.off] = '\0';
263     return info.off;
264 }
265
266 /*
267  * Local variables:
268  * c-basic-offset: 4
269  * c-file-style: "Stroustrup"
270  * indent-tabs-mode: nil
271  * End:
272  * vim: shiftwidth=4 tabstop=8 expandtab
273  */
274