48bb284c82f3acbb2bcc2c6462d6e7cc8bc3a7ef
[yaz-moved-to-github.git] / src / cql2ccl.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 cql2ccl.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 int cql_to_ccl_r(struct cql_node *cn, 
20                         void (*pr)(const char *buf, void *client_data),
21                         void *client_data);
22
23 static void pr_term(struct cql_node *cn,
24                     void (*pr)(const char *buf, void *client_data),
25                     void *client_data)
26 {
27     while (cn)
28     {
29         pr("\"", client_data);
30         pr(cn->u.st.term, client_data);
31         pr("\"", client_data);
32         if (cn->u.st.extra_terms)
33             pr(" ", client_data);
34         cn = cn->u.st.extra_terms;
35     }
36 }
37
38 static int node(struct cql_node *cn, 
39                 void (*pr)(const char *buf, void *client_data),
40                 void *client_data)
41 {
42     const char *ccl_field = 0;
43     const char *split_op = 0;
44     const char *ccl_rel = 0;
45     const char *rel = cn->u.st.relation;
46
47     if (cn->u.st.index && strcmp(cn->u.st.index,
48                                  "cql.serverChoice"))
49         ccl_field = cn->u.st.index;
50
51     if (!rel)
52         ;
53     else if (!strcmp(rel, "<") || !strcmp(rel, "<=")
54              || !strcmp(rel, ">") || !strcmp(rel, ">=")
55              || !strcmp(rel, "<>") || !strcmp(rel, "="))
56         ccl_rel = rel;
57     else if (!strcmp(rel, "all"))
58     {
59         ccl_rel = "=";
60         split_op = "and";
61     }
62     else if (!strcmp(rel, "any"))
63     {
64         ccl_rel = "=";
65         split_op = "or";
66     }
67     else if (!strcmp(rel, "==") || !strcmp(rel, "adj"))
68     {
69         ccl_rel = "=";
70     }
71     else
72     {
73         /* unsupported relation */
74         return -1;
75     }
76     if (!split_op)
77     {
78         if (ccl_field && ccl_rel)
79         {
80             pr(ccl_field, client_data);
81             pr(ccl_rel, client_data);
82         }
83         pr_term(cn, pr, client_data);
84     }
85     else
86     {
87         const char *cp = cn->u.st.term;
88         
89         while (1)
90         {
91             if (*cp == '\0')
92                 break;
93             if (ccl_field && ccl_rel)
94             {
95                 pr(ccl_field, client_data);
96                 pr(ccl_rel, client_data);
97             }
98             while (*cp && *cp != ' ')
99             {
100                 char x[2];
101                 x[0] = *cp;
102                 x[1] = '\0';
103                 pr(x, client_data);
104                 cp++;
105             }
106             while (*cp == ' ')
107                 cp++;
108             if (*cp == '\0')
109                 break;
110             pr(" ", client_data);
111             pr(split_op, client_data);
112             pr(" ", client_data);            
113         }
114     }
115     return 0;
116 }
117
118
119 static int bool(struct cql_node *cn, 
120                 void (*pr)(const char *buf, void *client_data),
121                 void *client_data)
122 {
123     int r;
124
125     pr("(", client_data);
126     r = cql_to_ccl_r(cn->u.boolean.left, pr, client_data);
127     if (r)
128         return r;
129     
130     pr(" ", client_data);
131     pr(cn->u.boolean.value, client_data);
132     pr(" ", client_data);
133
134     r = cql_to_ccl_r(cn->u.boolean.right, pr, client_data);
135     pr(")", client_data);
136     return r;
137 }
138
139 static int cql_to_ccl_r(struct cql_node *cn, 
140                         void (*pr)(const char *buf, void *client_data),
141                         void *client_data)
142 {
143     if (!cn)
144         return -1;
145
146     switch (cn->which)
147     {
148     case CQL_NODE_ST:
149         return node(cn, pr, client_data);
150     case CQL_NODE_BOOL:
151         return bool(cn, pr, client_data);
152     case CQL_NODE_SORT:
153         return cql_to_ccl_r(cn->u.sort.search, pr, client_data);
154     }
155     return -1;
156 }
157
158 int cql_to_ccl(struct cql_node *cn, 
159                void (*pr)(const char *buf, void *client_data),
160                void *client_data)
161 {
162     return cql_to_ccl_r(cn, pr, client_data);
163 }
164
165 void cql_to_ccl_stdio(struct cql_node *cn, FILE *f)
166 {
167     cql_to_ccl(cn, cql_fputs, f);
168 }
169
170 int cql_to_ccl_buf(struct cql_node *cn, char *out, int max)
171 {
172     struct cql_buf_write_info info;
173     int r;
174     info.off = 0;
175     info.max = max;
176     info.buf = out;
177     r = cql_to_ccl(cn, cql_buf_write_handler, &info);
178     if (info.off >= 0)
179         info.buf[info.off] = '\0';
180     else
181         return -2; /* buffer overflow */
182     return r;
183 }
184
185 /*
186  * Local variables:
187  * c-basic-offset: 4
188  * c-file-style: "Stroustrup"
189  * indent-tabs-mode: nil
190  * End:
191  * vim: shiftwidth=4 tabstop=8 expandtab
192  */
193