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