64-bit BER integers. Fixes bug #114.
[yaz-moved-to-github.git] / src / logrpn.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2009 Index Data
3  * See the file LICENSE for details.
4  */
5
6 /**
7  * \file logrpn.c
8  * \brief Implements Z39.50 Query Printing
9  */
10
11 #include <stdio.h>
12 #include <assert.h>
13
14 #include <yaz/log.h>
15 #include <yaz/logrpn.h>
16 #include <yaz/oid_db.h>
17
18 static const char *relToStr(int v)
19 {
20     const char *str = 0;
21     switch (v)
22     {
23     case 1: str = "Less than"; break;
24     case 2: str = "Less than or equal"; break;
25     case 3: str = "Equal"; break;
26     case 4: str = "Greater or equal"; break;
27     case 5: str = "Greater than"; break;
28     case 6: str = "Not equal"; break;
29     case 100: str = "Phonetic"; break;
30     case 101: str = "Stem"; break;
31     case 102: str = "Relevance"; break;
32     case 103: str = "AlwaysMatches"; break;
33     }
34     return str;
35 }
36
37 static void attrStr (int type, int value, char *str)
38 {
39     const char *rstr;
40     *str = '\0';
41     switch (type)
42     {
43     case 1:
44         sprintf (str, "use");
45         break;
46     case 2:
47         rstr = relToStr(value);
48         if (rstr)
49             sprintf(str, "relation=%s", rstr);
50         else
51             sprintf(str, "relation=%d", value);
52         break;
53     case 3:
54         switch (value)
55         {
56         case 1:
57             sprintf(str, "position=First in field");
58             break;
59         case 2:
60             sprintf(str, "position=First in any subfield");
61             break;
62         case 3:
63             sprintf(str, "position=Any position in field");
64             break;
65         default:
66             sprintf(str, "position");
67         }
68         break;
69     case 4:
70         switch (value)
71         {
72         case 1:
73             sprintf(str, "structure=Phrase");
74             break;
75         case 2:
76             sprintf(str, "structure=Word");
77             break;
78         case 3:
79             sprintf(str, "structure=Key");
80             break;
81         case 4:
82             sprintf(str, "structure=Year");
83             break;
84         case 5:
85             sprintf(str, "structure=Date");
86             break;
87         case 6:
88             sprintf(str, "structure=Word list");
89             break;
90         case 100:
91             sprintf(str, "structure=Date (un)");
92             break;
93         case 101:
94             sprintf(str, "structure=Name (norm)");
95             break;
96         case 102:
97             sprintf(str, "structure=Name (un)");
98             break;
99         case 103:
100             sprintf(str, "structure=Structure");
101             break;
102         case 104:
103             sprintf(str, "structure=urx");
104             break;
105         case 105:
106             sprintf(str, "structure=free-form-text");
107             break;
108         case 106:
109             sprintf(str, "structure=document-text");
110             break;
111         case 107:
112             sprintf(str, "structure=local-number");
113             break;
114         case 108:
115             sprintf(str, "structure=string");
116             break;
117         case 109:
118             sprintf(str, "structure=numeric string");
119             break;
120         default:
121             sprintf(str, "structure");
122         }
123         break;
124     case 5:
125         switch (value)
126         {
127         case 1:
128             sprintf(str, "truncation=Right");
129             break;
130         case 2:
131             sprintf(str, "truncation=Left");
132             break;
133         case 3:
134             sprintf(str, "truncation=Left&right");
135             break;
136         case 100:
137             sprintf(str, "truncation=Do not truncate");
138             break;
139         case 101:
140             sprintf(str, "truncation=Process #");
141             break;
142         case 102:
143             sprintf(str, "truncation=re-1");
144             break;
145         case 103:
146             sprintf(str, "truncation=re-2");
147             break;
148         case 104:
149             sprintf(str, "truncation=CCL");
150             break;
151         default:
152             sprintf(str, "truncation");
153         }
154         break;
155     case 6:
156         switch(value)
157         {
158         case 1:
159             sprintf(str, "completeness=Incomplete subfield");
160             break;
161         case 2:
162             sprintf(str, "completeness=Complete subfield");
163             break;
164         case 3:
165             sprintf(str, "completeness=Complete field");
166             break;
167         default:
168             sprintf(str, "completeness");
169         }
170         break;
171     }
172     if (*str)
173         sprintf(str + strlen(str), " (%d=%d)", type, value);
174     else
175         sprintf(str, "%d=%d", type, value);
176 }
177
178 /*
179  * zlog_attributes: print attributes of term
180  */
181 static void zlog_attributes(Z_AttributesPlusTerm *t, int depth,
182                             const Odr_oid *ast, int loglevel)
183 {
184     int of, i;
185     char str[80];
186     int num_attributes = t->attributes->num_attributes;
187     
188     for (of = 0; of < num_attributes; of++)
189     {
190         char attset_name_buf[OID_STR_MAX];
191         const char *attset_name = 0;
192         Z_AttributeElement *element;
193         element = t->attributes->attributes[of];
194         if (element->attributeSet)
195         {
196             attset_name = yaz_oid_to_string_buf(element->attributeSet,
197                                                 0, attset_name_buf);
198         }
199         if (!attset_name)
200             attset_name = "";
201         switch (element->which) 
202         {
203         case Z_AttributeValue_numeric:
204             attrStr (*element->attributeType,
205                      *element->value.numeric, str);
206             yaz_log (loglevel, "%*.0s%s %s", depth, "", attset_name, str);
207             break;
208         case Z_AttributeValue_complex:
209             yaz_log (loglevel, "%*.0s%s attributeType=" ODR_INT_PRINTF
210                      " complex",
211                   depth, "", attset_name, *element->attributeType);
212             for (i = 0; i<element->value.complex->num_list; i++)
213             {
214                 if (element->value.complex->list[i]->which ==
215                     Z_StringOrNumeric_string)
216                     yaz_log (loglevel, "%*.0s  string: '%s'", depth, "",
217                              element->value.complex->list[i]->u.string);
218                 else if (element->value.complex->list[i]->which ==
219                          Z_StringOrNumeric_numeric)
220                     yaz_log (loglevel, "%*.0s  numeric: '" ODR_INT_PRINTF
221                              " '", depth, "",
222                              *element->value.complex->list[i]->u.numeric);
223             }
224             break;
225         default:
226             yaz_log (loglevel, "%.*s%s attribute unknown",
227                      depth, "", attset_name);
228         }
229     }
230 }
231
232 static char *complex_op_name(Z_Operator *op)
233 {
234     switch (op->which)
235     {
236     case Z_Operator_and:
237         return "and";
238     case Z_Operator_or:
239         return "or";
240     case Z_Operator_and_not:
241         return "not";
242     case Z_Operator_prox:
243         return "prox";
244     default:
245         return "unknown complex operator";
246     }
247 }
248
249 static char *prox_unit_name(Z_ProximityOperator *op)
250 {
251     if (op->which!=Z_ProximityOperator_known)
252          return "private";
253     switch(*op->u.known)
254     {
255         case Z_ProxUnit_character: return "character";
256         case Z_ProxUnit_word: return "word";
257         case Z_ProxUnit_sentence: return "sentence";
258         case Z_ProxUnit_paragraph: return "paragraph";
259         case Z_ProxUnit_section: return "section";
260         case Z_ProxUnit_chapter: return "chapter";
261         case Z_ProxUnit_document: return "document";
262         case Z_ProxUnit_element: return "element";
263         case Z_ProxUnit_subelement: return "subelement";
264         case Z_ProxUnit_elementType: return "elementType";
265         case Z_ProxUnit_byte: return "byte";
266         default: return "unknown";
267     }
268 }
269
270 static void zlog_structure(Z_RPNStructure *zs, int depth, 
271                            const Odr_oid *ast, int loglevel)
272 {
273     if (zs->which == Z_RPNStructure_complex)
274     {
275         Z_Operator *op = zs->u.complex->roperator;
276         switch (op->which)
277         {
278         case Z_Operator_and:
279         case Z_Operator_or:
280         case Z_Operator_and_not:
281             yaz_log (loglevel, "%*.0s %s", depth, "", complex_op_name(op) );
282             break;
283         case Z_Operator_prox:
284             yaz_log (loglevel, "%*.0s prox excl=%s dist=" ODR_INT_PRINTF
285                      " order=%s "
286                      "rel=%s unit=%s",
287                      depth, "", op->u.prox->exclusion ?
288                      (*op->u.prox->exclusion ? "T" : "F") : "N", 
289                      *op->u.prox->distance,
290                      *op->u.prox->ordered ? "T" : "F",
291                      relToStr(*op->u.prox->relationType),
292                      prox_unit_name(op->u.prox) );
293             break;
294         default:
295             yaz_log (loglevel, "%*.0s unknown complex", depth, "");
296             return;
297         }
298         zlog_structure (zs->u.complex->s1, depth+2, ast, loglevel);
299         zlog_structure (zs->u.complex->s2, depth+2, ast, loglevel);
300     } 
301     else if (zs->which == Z_RPNStructure_simple)
302     {
303         if (zs->u.simple->which == Z_Operand_APT)
304         {
305             Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
306
307             switch (zapt->term->which)
308             {
309             case Z_Term_general:
310                 yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
311                          zapt->term->u.general->len,
312                          zapt->term->u.general->buf);
313                 break;
314             case Z_Term_characterString:
315                 yaz_log (loglevel, "%*.0s term '%s' (string)", depth, "",
316                          zapt->term->u.characterString);
317                 break;
318             case Z_Term_numeric:
319                 yaz_log (loglevel, "%*.0s term '" ODR_INT_PRINTF
320                          "' (numeric)", depth, "",
321                          *zapt->term->u.numeric);
322                 break;
323             case Z_Term_null:
324                 yaz_log (loglevel, "%*.0s term (null)", depth, "");
325                 break;
326             default:
327                 yaz_log (loglevel, "%*.0s term (not general)", depth, "");
328             }
329             zlog_attributes(zapt, depth+2, ast, loglevel);
330         }
331         else if (zs->u.simple->which == Z_Operand_resultSetId)
332         {
333             yaz_log (loglevel, "%*.0s set '%s'", depth, "",
334                      zs->u.simple->u.resultSetId);
335         }
336         else
337             yaz_log (loglevel, "%*.0s unknown simple structure", depth, "");
338     }
339     else
340         yaz_log (loglevel, "%*.0s unknown structure", depth, "");
341 }
342
343 void log_rpn_query_level (int loglevel, Z_RPNQuery *rpn)
344 {
345     zlog_structure(rpn->RPNStructure, 0, rpn->attributeSetId, loglevel);
346 }
347
348 void log_rpn_query(Z_RPNQuery *rpn)
349 {
350     log_rpn_query_level(YLOG_LOG, rpn);
351 }
352
353 void log_scan_term_level(int loglevel, 
354                          Z_AttributesPlusTerm *zapt, const Odr_oid *ast)
355 {
356     int depth = 0;
357     if (!loglevel)
358         return;
359     if (zapt->term->which == Z_Term_general) 
360     {
361         yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
362                  zapt->term->u.general->len, zapt->term->u.general->buf);
363     }
364     else
365         yaz_log (loglevel, "%*.0s term (not general)", depth, "");
366     zlog_attributes(zapt, depth+2, ast, loglevel);
367 }
368
369 void log_scan_term(Z_AttributesPlusTerm *zapt, const Odr_oid *ast)
370 {
371     log_scan_term_level (YLOG_LOG, zapt, ast);
372 }
373
374 void yaz_log_zquery_level (int loglevel, Z_Query *q)
375 {
376     if (!loglevel)
377         return; 
378     switch (q->which)
379     {
380     case Z_Query_type_1: case Z_Query_type_101:
381         log_rpn_query_level (loglevel, q->u.type_1);
382         break;
383     case Z_Query_type_2:
384         yaz_log(loglevel, "CCL: %.*s", q->u.type_2->len, q->u.type_2->buf);
385         break;
386     case Z_Query_type_100:
387         yaz_log(loglevel, "Z39.58: %.*s", q->u.type_100->len,
388                 q->u.type_100->buf);
389         break;
390     case Z_Query_type_104:
391         if (q->u.type_104->which == Z_External_CQL)
392             yaz_log (loglevel, "CQL: %s", q->u.type_104->u.cql);
393     }
394 }
395
396 void yaz_log_zquery (Z_Query *q)
397 {
398     yaz_log_zquery_level(YLOG_LOG, q);
399 }
400
401 /*
402  * Local variables:
403  * c-basic-offset: 4
404  * c-file-style: "Stroustrup"
405  * indent-tabs-mode: nil
406  * End:
407  * vim: shiftwidth=4 tabstop=8 expandtab
408  */
409