Re-implemented the element name encoding as Adams suggestion: <e tag="value"> when...
[yaz-moved-to-github.git] / src / querytowrbuf.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2010 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /** \file querytowrbuf.c
7     \brief Convert Z39.50 Z_Query to PQF (as WRBUF string)
8  */
9
10 #include <stdio.h>
11 #include <assert.h>
12
13 #include <yaz/logrpn.h>
14 #include <yaz/querytowrbuf.h>
15 #include <yaz/oid_db.h>
16
17 void yaz_encode_pqf_term(WRBUF b, const char *term, int len)
18 {
19     int i;
20     for (i = 0; i < len; i++)
21         if (strchr(" \"{", term[i]))
22             break;
23     if (i == len && i)
24         wrbuf_printf(b, "%.*s ", len, term);
25     else
26     {
27         wrbuf_putc(b, '"');
28         for (i = 0; i<len; i++)
29         {
30             if (term[i] == '"')
31                 wrbuf_putc(b, '\\');
32             wrbuf_putc(b, term[i]);
33         }
34         wrbuf_printf(b, "\" ");
35     }
36 }
37
38 static void yaz_attribute_element_to_wrbuf(WRBUF b,
39                                            const Z_AttributeElement *element)
40 {
41     int i;
42     char oid_name_str[OID_STR_MAX];
43     const char *setname = 0;
44     char *sep = " "; /* optional space after attrset name */
45     if (element->attributeSet)
46     {
47         setname = yaz_oid_to_string_buf(element->attributeSet, 
48                                         0, oid_name_str);
49     }
50     if (!setname)
51     {
52         setname = "";
53         sep = "";
54     }
55     switch (element->which) 
56     {
57     case Z_AttributeValue_numeric:
58         wrbuf_printf(b,"@attr %s%s" ODR_INT_PRINTF "=" ODR_INT_PRINTF " ",
59                      setname, sep,
60                      *element->attributeType, *element->value.numeric);
61         break;
62     case Z_AttributeValue_complex:
63         wrbuf_printf(b,"@attr %s%s\""ODR_INT_PRINTF "=", setname, sep,
64                      *element->attributeType);
65         for (i = 0; i<element->value.complex->num_list; i++)
66         {
67             if (i)
68                 wrbuf_printf(b,",");
69             if (element->value.complex->list[i]->which ==
70                 Z_StringOrNumeric_string)
71                 wrbuf_printf (b, "%s",
72                               element->value.complex->list[i]->u.string);
73             else if (element->value.complex->list[i]->which ==
74                      Z_StringOrNumeric_numeric)
75                 wrbuf_printf (b, ODR_INT_PRINTF, 
76                               *element->value.complex->list[i]->u.numeric);
77         }
78         wrbuf_printf(b, "\" ");
79         break;
80     default:
81         wrbuf_printf (b, "@attr 1=unknown ");
82     }
83 }
84
85 static const char *complex_op_name(const Z_Operator *op)
86 {
87     switch (op->which)
88     {
89     case Z_Operator_and:
90         return "and";
91     case Z_Operator_or:
92         return "or";
93     case Z_Operator_and_not:
94         return "not";
95     case Z_Operator_prox:
96         return "prox";
97     default:
98         return "unknown complex operator";
99     }
100 }
101
102 static void yaz_apt_to_wrbuf(WRBUF b, const Z_AttributesPlusTerm *zapt)
103 {
104     int num_attributes = zapt->attributes->num_attributes;
105     int i;
106     for (i = 0; i<num_attributes; i++)
107         yaz_attribute_element_to_wrbuf(b,zapt->attributes->attributes[i]);
108     
109     switch (zapt->term->which)
110     {
111     case Z_Term_general:
112         yaz_encode_pqf_term(b, (const char *)zapt->term->u.general->buf,
113                             zapt->term->u.general->len);
114         break;
115     case Z_Term_characterString:
116         wrbuf_printf(b, "@term string ");
117         yaz_encode_pqf_term(b, zapt->term->u.characterString,
118                             strlen(zapt->term->u.characterString));
119         break;
120     case Z_Term_numeric:
121         wrbuf_printf(b, "@term numeric " ODR_INT_PRINTF " ",
122                      *zapt->term->u.numeric);
123         break;
124     case Z_Term_null:
125         wrbuf_printf(b, "@term null x");
126         break;
127     default:
128         wrbuf_printf(b, "@term null unknown%d ", zapt->term->which);
129     }
130 }
131
132 static void yaz_rpnstructure_to_wrbuf(WRBUF b, const Z_RPNStructure *zs)
133 {
134     if (zs->which == Z_RPNStructure_complex)
135     {
136         Z_Operator *op = zs->u.complex->roperator;
137         wrbuf_printf(b, "@%s ", complex_op_name(op) );
138         if (op->which== Z_Operator_prox)
139         {
140             if (!op->u.prox->exclusion)
141                 wrbuf_putc(b, 'n');
142             else if (*op->u.prox->exclusion)
143                 wrbuf_putc(b, '1');
144             else
145                 wrbuf_putc(b, '0');
146
147             wrbuf_printf(b, " " ODR_INT_PRINTF " %d " 
148                          ODR_INT_PRINTF " ", *op->u.prox->distance,
149                          *op->u.prox->ordered,
150                          *op->u.prox->relationType);
151
152             switch(op->u.prox->which)
153             {
154             case Z_ProximityOperator_known:
155                 wrbuf_putc(b, 'k');
156                 break;
157             case Z_ProximityOperator_private:
158                 wrbuf_putc(b, 'p');
159                 break;
160             default:
161                 wrbuf_printf(b, "%d", op->u.prox->which);
162             }
163             if (op->u.prox->u.known)
164                 wrbuf_printf(b, " " ODR_INT_PRINTF " ", *op->u.prox->u.known);
165             else
166                 wrbuf_printf(b, " 0 ");
167         }
168         yaz_rpnstructure_to_wrbuf(b,zs->u.complex->s1);
169         yaz_rpnstructure_to_wrbuf(b,zs->u.complex->s2);
170     }
171     else if (zs->which == Z_RPNStructure_simple)
172     {
173         if (zs->u.simple->which == Z_Operand_APT)
174             yaz_apt_to_wrbuf(b, zs->u.simple->u.attributesPlusTerm);
175         else if (zs->u.simple->which == Z_Operand_resultSetId)
176         {
177             wrbuf_printf(b, "@set ");
178             yaz_encode_pqf_term(b, zs->u.simple->u.resultSetId,
179                                 strlen(zs->u.simple->u.resultSetId));
180         }
181         else
182             wrbuf_printf (b, "(unknown simple structure)");
183     }
184     else
185         wrbuf_puts(b, "(unknown structure)");
186 }
187
188 void yaz_rpnquery_to_wrbuf(WRBUF b, const Z_RPNQuery *rpn)
189 {
190     if (rpn->attributeSetId)
191     {
192         char oid_name_str[OID_STR_MAX];
193         const char *oid_name = yaz_oid_to_string_buf(rpn->attributeSetId,
194                                                      0, oid_name_str);
195         if (oid_name)
196             wrbuf_printf(b, "@attrset %s ", oid_name);
197     } 
198     yaz_rpnstructure_to_wrbuf(b, rpn->RPNStructure);
199     wrbuf_chop_right(b);
200 }
201
202 void yaz_query_to_wrbuf(WRBUF b, const Z_Query *q)
203 {
204     assert(q);
205     assert(b);
206     switch (q->which)
207     {
208     case Z_Query_type_1: 
209     case Z_Query_type_101:
210         wrbuf_printf(b,"RPN ");
211         yaz_rpnquery_to_wrbuf(b, q->u.type_1);
212         break;
213     case Z_Query_type_2:
214         wrbuf_printf(b, "CCL %.*s", q->u.type_2->len, q->u.type_2->buf);
215         break;
216     case Z_Query_type_100:
217         wrbuf_printf(b, "Z39.58 %.*s", q->u.type_100->len,
218                      q->u.type_100->buf);
219         break;
220     case Z_Query_type_104:
221         if (q->u.type_104->which == Z_External_CQL)
222             wrbuf_printf(b, "CQL %s", q->u.type_104->u.cql);
223         else
224             wrbuf_printf(b,"UNKNOWN type 104 query %d", q->u.type_104->which);
225     }
226 }
227
228 void yaz_scan_to_wrbuf(WRBUF b, const Z_AttributesPlusTerm *zapt,
229                        const Odr_oid *attrbute_set)
230 {
231     /* should print attr set here */
232     wrbuf_printf(b, "RPN ");
233     yaz_apt_to_wrbuf(b, zapt);
234 }
235
236 void wrbuf_diags(WRBUF b, int num_diagnostics, Z_DiagRec **diags)
237 {
238     /* we only dump the first diag - that keeps the log cleaner. */
239     wrbuf_printf(b," ERROR ");
240     if (diags[0]->which != Z_DiagRec_defaultFormat)
241         wrbuf_printf(b,"(diag not in default format?)");
242     else
243     {
244         Z_DefaultDiagFormat *e=diags[0]->u.defaultFormat;
245         if (e->condition)
246             wrbuf_printf(b, ODR_INT_PRINTF " ",*e->condition);
247         else
248             wrbuf_printf(b, "?? ");
249         if ((e->which==Z_DefaultDiagFormat_v2Addinfo) && (e->u.v2Addinfo))
250             wrbuf_printf(b,"%s ",e->u.v2Addinfo);
251         else if ((e->which==Z_DefaultDiagFormat_v3Addinfo) && (e->u.v3Addinfo))
252             wrbuf_printf(b,"%s ",e->u.v3Addinfo);
253     }
254 }
255
256 /*
257  * Local variables:
258  * c-basic-offset: 4
259  * c-file-style: "Stroustrup"
260  * indent-tabs-mode: nil
261  * End:
262  * vim: shiftwidth=4 tabstop=8 expandtab
263  */
264