First RPN to CQL conversion using actual attribute matching.
[yaz-moved-to-github.git] / src / rpn2cql.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
8  * \brief Implements RPN to CQL conversion
9  *
10  */
11
12 #include <assert.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <yaz/rpn2cql.h>
16 #include <yaz/xmalloc.h>
17 #include <yaz/diagbib1.h>
18 #include <yaz/z-core.h>
19 #include <yaz/wrbuf.h>
20
21 static int rpn2cql_attr(cql_transform_t ct,
22                         Z_AttributeList *attributes, WRBUF w)
23 {
24     const char *relation = cql_lookup_reverse(ct, "relation.", attributes);
25     const char *index = cql_lookup_reverse(ct, "index.", attributes);
26     const char *structure = cql_lookup_reverse(ct, "structure.", attributes);
27     if (index && strcmp(index, "index.cql.serverChoice"))
28     {
29         wrbuf_puts(w, index+6);
30         if (relation)
31         {
32             relation += 9;
33
34             if (!strcmp(relation, "exact"))
35                 relation = "==";
36             else if (!strcmp(relation, "eq"))
37                 relation = "=";
38             else if (!strcmp(relation, "le"))
39                 relation = "<=";
40             else if (!strcmp(relation, "ge"))
41                 relation = ">=";
42             wrbuf_puts(w, relation);
43         }
44         else
45             wrbuf_puts(w, "=");
46
47         if (structure)
48         {
49             structure += 10;
50             if (strcmp(structure, "*"))
51             {
52                 wrbuf_puts(w, "/");
53                 wrbuf_puts(w, structure);
54                 wrbuf_puts(w, " ");
55             }
56         }
57     }
58     return 0;
59 }
60
61 static int rpn2cql_simple(cql_transform_t ct,
62                           void (*pr)(const char *buf, void *client_data),
63                           void *client_data,
64                           Z_Operand *q, WRBUF w)
65 {
66     int ret = 0;
67     if (q->which != Z_Operand_APT)
68     {
69         ret = -1;
70         cql_transform_set_error(ct, YAZ_BIB1_RESULT_SET_UNSUPP_AS_A_SEARCH_TERM, 0);
71     }
72     else
73     {
74         Z_AttributesPlusTerm *apt = q->u.attributesPlusTerm;
75         Z_Term *term = apt->term;
76         const char *sterm = 0;
77         size_t lterm = 0;
78
79         wrbuf_rewind(w);
80         ret = rpn2cql_attr(ct, apt->attributes, w);
81
82         switch(term->which)
83         {
84         case Z_Term_general:
85             lterm = term->u.general->len;
86             sterm = (const char *) term->u.general->buf;
87             break;
88         case Z_Term_numeric:
89             wrbuf_printf(w, "%d", *term->u.numeric);
90             break;
91         case Z_Term_characterString:
92             sterm = term->u.characterString;
93             lterm = strlen(sterm);
94             break;
95         default:
96             ret = -1;
97             cql_transform_set_error(ct, YAZ_BIB1_TERM_TYPE_UNSUPP, 0);
98         }
99
100         if (term)
101         {
102             int i;
103             int must_quote = 0;
104             for (i = 0 ; i < lterm; i++)
105                 if (sterm[i] == ' ')
106                     must_quote = 1;
107             if (must_quote)
108                 wrbuf_puts(w, "\"");
109             wrbuf_write(w, sterm, lterm);
110             if (must_quote)
111                 wrbuf_puts(w, "\"");
112         }
113         if (ret == 0)
114             pr(wrbuf_cstr(w), client_data);
115     }
116     return ret;
117 }
118
119 static int rpn2cql_structure(cql_transform_t ct,
120                              void (*pr)(const char *buf, void *client_data),
121                              void *client_data,
122                              Z_RPNStructure *q, int nested,
123                              WRBUF w)
124 {
125     if (q->which == Z_RPNStructure_simple)
126         return rpn2cql_simple(ct, pr, client_data, q->u.simple, w);
127     else
128     {
129         Z_Operator *op = q->u.complex->roperator;
130         int r;
131
132         if (nested)
133             pr("(", client_data);
134
135         r = rpn2cql_structure(ct, pr, client_data, q->u.complex->s1, 1, w);
136         if (r)
137             return r;
138         switch(op->which)
139         {
140         case  Z_Operator_and:
141             pr(" and ", client_data);
142             break;
143         case  Z_Operator_or:
144             pr(" or ", client_data);
145             break;
146         case  Z_Operator_and_not:
147             pr(" not ", client_data);
148             break;
149         case  Z_Operator_prox:
150             cql_transform_set_error(ct, YAZ_BIB1_UNSUPP_SEARCH, 0);
151             return -1;
152         }
153         r = rpn2cql_structure(ct, pr, client_data, q->u.complex->s2, 1, w);
154         if (nested)
155             pr(")", client_data);
156         return r;
157     }
158 }
159
160 int cql_transform_rpn2cql_stream(cql_transform_t ct,
161                                  void (*pr)(const char *buf, void *client_data),
162                                  void *client_data,
163                                  Z_RPNQuery *q)
164 {
165     int r;
166     WRBUF w = wrbuf_alloc();
167     cql_transform_set_error(ct, 0, 0);
168     r = rpn2cql_structure(ct, pr, client_data, q->RPNStructure, 0, w);
169     wrbuf_destroy(w);
170     return r;
171 }
172
173
174 int cql_transform_rpn2cql_wrbuf(cql_transform_t ct,
175                                 WRBUF w,
176                                 Z_RPNQuery *q)
177 {
178     return cql_transform_rpn2cql_stream(ct, wrbuf_vputs, w, q);
179 }
180
181 /*
182  * Local variables:
183  * c-basic-offset: 4
184  * indent-tabs-mode: nil
185  * End:
186  * vim: shiftwidth=4 tabstop=8 expandtab
187  */
188