Fix left-right truncation fix
[yaz-moved-to-github.git] / src / xcqlutil.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2011 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_to_xml_r(struct cql_node *cn,
122                          void (*pr)(const char *buf, void *client_data),
123                          void *client_data, int level)
124 {
125     if (!cn)
126         return;
127     switch (cn->which)
128     {
129     case CQL_NODE_ST:
130         pr_n("<searchClause>\n", pr, client_data, level);
131         prefixes(cn, pr, client_data, level+2);
132         if (cn->u.st.index)
133         {
134             pr_n("<index>", pr, client_data, level+2);
135             pr_cdata(cn->u.st.index, pr, client_data);
136             pr_n("</index>\n", pr, client_data, 0);
137         }
138         if (cn->u.st.relation)
139         {
140             pr_n("<relation>\n", pr, client_data, level+2);
141             pr_n("<value>", pr, client_data, level+4);
142             if (cn->u.st.relation_uri)
143                 pr_cdata("rel.", pr, client_data);
144             pr_cdata(cn->u.st.relation, pr, client_data);
145             pr_n("</value>\n", pr, client_data, 0);
146
147             if (cn->u.st.relation_uri)
148             {
149                 pr_n("<identifier>", pr, client_data, level+4);
150                 pr_cdata(cn->u.st.relation_uri, pr, client_data);
151                 pr_n("</identifier>\n", pr, client_data, 0);
152             }
153             cql_to_xml_mod(cn->u.st.modifiers,
154                            pr, client_data, level+4);
155
156             pr_n("</relation>\n", pr, client_data, level+2);
157         }
158         if (cn->u.st.term)
159         {
160             pr_n("<term>", pr, client_data, level+2);
161             pr_cdata(cn->u.st.term, pr, client_data);
162             pr_n("</term>\n", pr, client_data, 0);
163         }
164         if (cn->u.st.extra_terms)
165         {
166             struct cql_node *n = cn->u.st.extra_terms;
167             for (; n; n = n->u.st.extra_terms)
168             {
169                 pr_n("<term>", pr, client_data, level+2);
170                 pr_cdata(n->u.st.term, pr, client_data);
171                 pr_n("</term>\n", pr, client_data, 0);
172             }
173         }
174         pr_n("</searchClause>\n", pr, client_data, level);
175         break;
176     case CQL_NODE_BOOL:
177         pr_n("<triple>\n", pr, client_data, level);
178         if (cn->u.boolean.value)
179         {
180             pr_n("<boolean>\n", pr, client_data, level+2);
181
182             pr_n("<value>", pr, client_data, level+4);
183             pr_cdata(cn->u.boolean.value, pr, client_data);
184             pr_n("</value>\n", pr, client_data, 0);
185
186             cql_to_xml_mod(cn->u.boolean.modifiers,
187                            pr, client_data, level+4);
188
189             pr_n("</boolean>\n", pr, client_data, level+2);
190         }
191         if (cn->u.boolean.left)
192         {
193             printf ("%*s<leftOperand>\n", level+2, "");
194             cql_to_xml_r(cn->u.boolean.left, pr, client_data, level+4);
195             printf ("%*s</leftOperand>\n", level+2, "");
196         }
197         if (cn->u.boolean.right)
198         {
199             printf ("%*s<rightOperand>\n", level+2, "");
200             cql_to_xml_r(cn->u.boolean.right, pr, client_data, level+4);
201             printf ("%*s</rightOperand>\n", level+2, "");
202         }
203         pr_n("</triple>\n", pr, client_data, level);
204     }
205 }
206
207 void cql_to_xml(struct cql_node *cn, 
208                 void (*pr)(const char *buf, void *client_data),
209                 void *client_data)
210 {
211     cql_to_xml_r(cn, pr, client_data, 0);
212 }
213
214 void cql_to_xml_stdio(struct cql_node *cn, FILE *f)
215 {
216     cql_to_xml(cn, cql_fputs, f);
217 }
218
219 void cql_buf_write_handler (const char *b, void *client_data)
220 {
221     struct cql_buf_write_info *info = (struct cql_buf_write_info *)client_data;
222     int l = strlen(b);
223     if (info->off < 0 || (info->off + l >= info->max))
224     {
225         info->off = -1;
226         return;
227     }
228     memcpy (info->buf + info->off, b, l);
229     info->off += l;
230 }
231
232 int cql_to_xml_buf(struct cql_node *cn, char *out, int max)
233 {
234     struct cql_buf_write_info info;
235     info.off = 0;
236     info.max = max;
237     info.buf = out;
238     cql_to_xml(cn, cql_buf_write_handler, &info);
239     if (info.off >= 0)
240         info.buf[info.off] = '\0';
241     return info.off;
242 }
243
244 /*
245  * Local variables:
246  * c-basic-offset: 4
247  * c-file-style: "Stroustrup"
248  * indent-tabs-mode: nil
249  * End:
250  * vim: shiftwidth=4 tabstop=8 expandtab
251  */
252