Update cql.y for newer bison YAZ-720
[yaz-moved-to-github.git] / src / xcqlutil.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 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         if (cn->u.st.extra_terms)
192         {
193             struct cql_node *n = cn->u.st.extra_terms;
194             for (; n; n = n->u.st.extra_terms)
195             {
196                 pr_n("<term>", pr, client_data, level+2);
197                 pr_cdata(n->u.st.term, pr, client_data);
198                 pr_n("</term>\n", pr, client_data, 0);
199             }
200         }
201         cql_sort_to_xml(sort_node, pr, client_data, level+2);
202         pr_n("</searchClause>\n", pr, client_data, level);
203         break;
204     case CQL_NODE_BOOL:
205         pr_n("<triple>\n", pr, client_data, level);
206         if (cn->u.boolean.value)
207         {
208             pr_n("<boolean>\n", pr, client_data, level+2);
209
210             pr_n("<value>", pr, client_data, level+4);
211             pr_cdata(cn->u.boolean.value, pr, client_data);
212             pr_n("</value>\n", pr, client_data, 0);
213
214             cql_to_xml_mod(cn->u.boolean.modifiers,
215                            pr, client_data, level+4);
216
217             pr_n("</boolean>\n", pr, client_data, level+2);
218         }
219         if (cn->u.boolean.left)
220         {
221             printf ("%*s<leftOperand>\n", level+2, "");
222             cql_to_xml_r(cn->u.boolean.left, pr, client_data, level+4, 0);
223             printf ("%*s</leftOperand>\n", level+2, "");
224         }
225         if (cn->u.boolean.right)
226         {
227             printf ("%*s<rightOperand>\n", level+2, "");
228             cql_to_xml_r(cn->u.boolean.right, pr, client_data, level+4, 0);
229             printf ("%*s</rightOperand>\n", level+2, "");
230         }
231         cql_sort_to_xml(sort_node, pr, client_data, level+2);
232         pr_n("</triple>\n", pr, client_data, level);
233         break;
234     case CQL_NODE_SORT:
235         cql_to_xml_r(cn->u.sort.search, pr, client_data, level, cn);
236     }
237 }
238
239 void cql_to_xml(struct cql_node *cn,
240                 void (*pr)(const char *buf, void *client_data),
241                 void *client_data)
242 {
243     cql_to_xml_r(cn, pr, client_data, 0, 0);
244 }
245
246 void cql_to_xml_stdio(struct cql_node *cn, FILE *f)
247 {
248     cql_to_xml(cn, cql_fputs, f);
249 }
250
251 void cql_buf_write_handler (const char *b, void *client_data)
252 {
253     struct cql_buf_write_info *info = (struct cql_buf_write_info *)client_data;
254     int l = strlen(b);
255     if (info->off < 0 || (info->off + l >= info->max))
256     {
257         info->off = -1;
258         return;
259     }
260     memcpy (info->buf + info->off, b, l);
261     info->off += l;
262 }
263
264 int cql_to_xml_buf(struct cql_node *cn, char *out, int max)
265 {
266     struct cql_buf_write_info info;
267     info.off = 0;
268     info.max = max;
269     info.buf = out;
270     cql_to_xml(cn, cql_buf_write_handler, &info);
271     if (info.off >= 0)
272         info.buf[info.off] = '\0';
273     return info.off;
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