Update source headers for 2008. Omit CVS ID keyword subst.
[yaz-moved-to-github.git] / src / logrpn.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 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=%d complex",
210                   depth, "", attset_name, *element->attributeType);
211             for (i = 0; i<element->value.complex->num_list; i++)
212             {
213                 if (element->value.complex->list[i]->which ==
214                     Z_StringOrNumeric_string)
215                     yaz_log (loglevel, "%*.0s  string: '%s'", depth, "",
216                              element->value.complex->list[i]->u.string);
217                 else if (element->value.complex->list[i]->which ==
218                          Z_StringOrNumeric_numeric)
219                     yaz_log (loglevel, "%*.0s  numeric: '%d'", depth, "",
220                              *element->value.complex->list[i]->u.numeric);
221             }
222             break;
223         default:
224             yaz_log (loglevel, "%.*s%s attribute unknown",
225                      depth, "", attset_name);
226         }
227     }
228 }
229
230 static char *complex_op_name(Z_Operator *op)
231 {
232     switch (op->which)
233     {
234     case Z_Operator_and:
235         return "and";
236     case Z_Operator_or:
237         return "or";
238     case Z_Operator_and_not:
239         return "not";
240     case Z_Operator_prox:
241         return "prox";
242     default:
243         return "unknown complex operator";
244     }
245 }
246
247 static char *prox_unit_name(Z_ProximityOperator *op)
248 {
249     if (op->which!=Z_ProximityOperator_known)
250          return "private";
251     switch(*op->u.known)
252     {
253         case Z_ProxUnit_character: return "character";
254         case Z_ProxUnit_word: return "word";
255         case Z_ProxUnit_sentence: return "sentence";
256         case Z_ProxUnit_paragraph: return "paragraph";
257         case Z_ProxUnit_section: return "section";
258         case Z_ProxUnit_chapter: return "chapter";
259         case Z_ProxUnit_document: return "document";
260         case Z_ProxUnit_element: return "element";
261         case Z_ProxUnit_subelement: return "subelement";
262         case Z_ProxUnit_elementType: return "elementType";
263         case Z_ProxUnit_byte: return "byte";
264         default: return "unknown";
265     }
266 }
267
268 static void zlog_structure(Z_RPNStructure *zs, int depth, 
269                            const Odr_oid *ast, int loglevel)
270 {
271     if (zs->which == Z_RPNStructure_complex)
272     {
273         Z_Operator *op = zs->u.complex->roperator;
274         switch (op->which)
275         {
276         case Z_Operator_and:
277         case Z_Operator_or:
278         case Z_Operator_and_not:
279             yaz_log (loglevel, "%*.0s %s", depth, "", complex_op_name(op) );
280             break;
281         case Z_Operator_prox:
282             yaz_log (loglevel, "%*.0s prox excl=%s dist=%d order=%s "
283                      "rel=%s unit=%s",
284                      depth, "", op->u.prox->exclusion ?
285                      (*op->u.prox->exclusion ? "T" : "F") : "N", 
286                      *op->u.prox->distance,
287                      *op->u.prox->ordered ? "T" : "F",
288                      relToStr(*op->u.prox->relationType),
289                      prox_unit_name(op->u.prox) );
290             break;
291         default:
292             yaz_log (loglevel, "%*.0s unknown complex", depth, "");
293             return;
294         }
295         zlog_structure (zs->u.complex->s1, depth+2, ast, loglevel);
296         zlog_structure (zs->u.complex->s2, depth+2, ast, loglevel);
297     } 
298     else if (zs->which == Z_RPNStructure_simple)
299     {
300         if (zs->u.simple->which == Z_Operand_APT)
301         {
302             Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
303
304             switch (zapt->term->which)
305             {
306             case Z_Term_general:
307                 yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
308                          zapt->term->u.general->len,
309                          zapt->term->u.general->buf);
310                 break;
311             case Z_Term_characterString:
312                 yaz_log (loglevel, "%*.0s term '%s' (string)", depth, "",
313                          zapt->term->u.characterString);
314                 break;
315             case Z_Term_numeric:
316                 yaz_log (loglevel, "%*.0s term '%d' (numeric)", depth, "",
317                          *zapt->term->u.numeric);
318                 break;
319             case Z_Term_null:
320                 yaz_log (loglevel, "%*.0s term (null)", depth, "");
321                 break;
322             default:
323                 yaz_log (loglevel, "%*.0s term (not general)", depth, "");
324             }
325             zlog_attributes(zapt, depth+2, ast, loglevel);
326         }
327         else if (zs->u.simple->which == Z_Operand_resultSetId)
328         {
329             yaz_log (loglevel, "%*.0s set '%s'", depth, "",
330                      zs->u.simple->u.resultSetId);
331         }
332         else
333             yaz_log (loglevel, "%*.0s unknown simple structure", depth, "");
334     }
335     else
336         yaz_log (loglevel, "%*.0s unknown structure", depth, "");
337 }
338
339 void log_rpn_query_level (int loglevel, Z_RPNQuery *rpn)
340 {
341     zlog_structure(rpn->RPNStructure, 0, rpn->attributeSetId, loglevel);
342 }
343
344 void log_rpn_query(Z_RPNQuery *rpn)
345 {
346     log_rpn_query_level(YLOG_LOG, rpn);
347 }
348
349 void log_scan_term_level(int loglevel, 
350                          Z_AttributesPlusTerm *zapt, const Odr_oid *ast)
351 {
352     int depth = 0;
353     if (!loglevel)
354         return;
355     if (zapt->term->which == Z_Term_general) 
356     {
357         yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
358                  zapt->term->u.general->len, zapt->term->u.general->buf);
359     }
360     else
361         yaz_log (loglevel, "%*.0s term (not general)", depth, "");
362     zlog_attributes(zapt, depth+2, ast, loglevel);
363 }
364
365 void log_scan_term(Z_AttributesPlusTerm *zapt, const Odr_oid *ast)
366 {
367     log_scan_term_level (YLOG_LOG, zapt, ast);
368 }
369
370 void yaz_log_zquery_level (int loglevel, Z_Query *q)
371 {
372     if (!loglevel)
373         return; 
374     switch (q->which)
375     {
376     case Z_Query_type_1: case Z_Query_type_101:
377         log_rpn_query_level (loglevel, q->u.type_1);
378         break;
379     case Z_Query_type_2:
380         yaz_log(loglevel, "CCL: %.*s", q->u.type_2->len, q->u.type_2->buf);
381         break;
382     case Z_Query_type_100:
383         yaz_log(loglevel, "Z39.58: %.*s", q->u.type_100->len,
384                 q->u.type_100->buf);
385         break;
386     case Z_Query_type_104:
387         if (q->u.type_104->which == Z_External_CQL)
388             yaz_log (loglevel, "CQL: %s", q->u.type_104->u.cql);
389     }
390 }
391
392 void yaz_log_zquery (Z_Query *q)
393 {
394     yaz_log_zquery_level(YLOG_LOG, q);
395 }
396
397 /*
398  * Local variables:
399  * c-basic-offset: 4
400  * indent-tabs-mode: nil
401  * End:
402  * vim: shiftwidth=4 tabstop=8 expandtab
403  */
404