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