Avoid new ANSI inline declaration
[yaz-moved-to-github.git] / src / logrpn.c
1 /*
2  * Copyright (C) 1995-2004, Index Data
3  * All rights reserved.
4  *
5  * $Id: logrpn.c,v 1.5 2004-11-16 22:10:29 adam Exp $
6  */
7
8 /**
9  * \file logrpn.c
10  * \brief Implements Z39.50 Query Printing
11  */
12
13 #include <stdio.h>
14 #include <assert.h>
15
16 #include <yaz/log.h>
17 #include <yaz/logrpn.h>
18
19 static const char *relToStr(int v)
20 {
21     const char *str = 0;
22     switch (v)
23     {
24     case 1: str = "Less than"; break;
25     case 2: str = "Less than or equal"; break;
26     case 3: str = "Equal"; break;
27     case 4: str = "Greater or equal"; break;
28     case 5: str = "Greater than"; break;
29     case 6: str = "Not equal"; break;
30     case 100: str = "Phonetic"; break;
31     case 101: str = "Stem"; break;
32     case 102: str = "Relevance"; break;
33     case 103: str = "AlwaysMatches"; break;
34     }
35     return str;
36 }
37 static void attrStr (int type, int value, enum oid_value ast, char *str)
38 {
39     const char *rstr;
40     *str = '\0';
41     switch (ast)
42     {
43     case VAL_BIB1:
44     case VAL_EXP1:
45     case VAL_GILS:
46         switch (type)
47         {
48         case 1:
49             sprintf (str, "use");
50             break;
51         case 2:
52             rstr = relToStr(value);
53             if (rstr)
54                 sprintf (str, "relation=%s", rstr);
55             else
56                 sprintf (str, "relation=%d", value);
57             break;
58         case 3:
59             switch (value)
60             {
61             case 1:
62                 sprintf (str, "position=First in field");
63                 break;
64             case 2:
65                 sprintf (str, "position=First in any subfield");
66                 break;
67             case 3:
68                 sprintf (str, "position=Any position in field");
69                 break;
70             default:
71                 sprintf (str, "position");
72             }
73             break;
74         case 4:
75             switch (value)
76             {
77             case 1:
78                 sprintf (str, "structure=Phrase");
79                 break;
80             case 2:
81                 sprintf (str, "structure=Word");
82                 break;
83             case 3:
84                 sprintf (str, "structure=Key");
85                 break;
86             case 4:
87                 sprintf (str, "structure=Year");
88                 break;
89             case 5:
90                 sprintf (str, "structure=Date");
91                 break;
92             case 6:
93                 sprintf (str, "structure=Word list");
94                 break;
95             case 100:
96                 sprintf (str, "structure=Date (un)");
97                 break;
98             case 101:
99                 sprintf (str, "structure=Name (norm)");
100                 break;
101             case 102:
102                 sprintf (str, "structure=Name (un)");
103                 break;
104             case 103:
105                 sprintf (str, "structure=Structure");
106                 break;
107             case 104:
108                 sprintf (str, "structure=urx");
109                 break;
110             case 105:
111                 sprintf (str, "structure=free-form-text");
112                 break;
113             case 106:
114                 sprintf (str, "structure=document-text");
115                 break;
116             case 107:
117                 sprintf (str, "structure=local-number");
118                 break;
119             case 108:
120                 sprintf (str, "structure=string");
121                 break;
122             case 109:
123                 sprintf (str, "structure=numeric string");
124                 break;
125             default:
126                 sprintf (str, "structure");
127             }
128             break;
129         case 5:
130             switch (value)
131             {
132             case 1:
133                 sprintf (str, "truncation=Right");
134                 break;
135             case 2:
136                 sprintf (str, "truncation=Left");
137                 break;
138             case 3:
139                 sprintf (str, "truncation=Left&right");
140                 break;
141             case 100:
142                 sprintf (str, "truncation=Do not truncate");
143                 break;
144             case 101:
145                 sprintf (str, "truncation=Process #");
146                 break;
147             case 102:
148                 sprintf (str, "truncation=re-1");
149                 break;
150             case 103:
151                 sprintf (str, "truncation=re-2");
152                 break;
153             case 104:
154                 sprintf (str, "truncation=CCL");
155                 break;
156             default:
157                 sprintf (str, "truncation");
158             }
159             break;
160         case 6:
161             switch (value)
162             {
163             case 1:
164                 sprintf (str, "completeness=Incomplete subfield");
165                 break;
166             case 2:
167                 sprintf (str, "completeness=Complete subfield");
168                 break;
169             case 3:
170                 sprintf (str, "completeness=Complete field");
171                 break;
172             default:
173                 sprintf (str, "completeness");
174             }
175             break;
176         }
177         break;
178     default:
179         break;
180     }
181     if (*str)
182         sprintf (str + strlen(str), " (%d=%d)", type, value);
183     else
184         sprintf (str, "%d=%d", type, value);
185 }
186
187 static void wrbuf_attr(WRBUF b, Z_AttributeElement *element)
188 {
189     int i;
190     char *setname="";
191     char *sep=""; /* optional space after attrset name */
192     if (element->attributeSet)
193     {
194         oident *attrset;
195         attrset = oid_getentbyoid (element->attributeSet);
196         setname=attrset->desc;
197         sep=" ";
198     }
199     switch (element->which) 
200     {
201         case Z_AttributeValue_numeric:
202             wrbuf_printf(b,"@attr %s%s%d=%d ", setname,sep,
203                     *element->attributeType, *element->value.numeric);
204             break;
205         case Z_AttributeValue_complex:
206             wrbuf_printf(b,"@attr %s%s%d=", setname,sep,*element->attributeType);
207             for (i = 0; i<element->value.complex->num_list; i++)
208             {
209                 if (i)
210                     wrbuf_printf(b,",");
211                 if (element->value.complex->list[i]->which ==
212                     Z_StringOrNumeric_string)
213                     wrbuf_printf (b, "'%s'",
214                              element->value.complex->list[i]->u.string);
215                 else if (element->value.complex->list[i]->which ==
216                          Z_StringOrNumeric_numeric)
217                     wrbuf_printf (b, "%d", 
218                              *element->value.complex->list[i]->u.numeric);
219             }
220             wrbuf_printf(b," ");
221             break;
222         default:
223             wrbuf_printf (b, "(unknown attr type) ");
224                      
225     }
226 }
227
228 /*
229  * zlog_attributes: print attributes of term
230  */
231 static void zlog_attributes (Z_AttributesPlusTerm *t, int depth,
232                              enum oid_value ast, int loglevel)
233 {
234     int of, i;
235     char str[80];
236     int num_attributes = t->attributes->num_attributes;
237     
238     for (of = 0; of < num_attributes; of++)
239     {
240         const char *attset_name = "";
241         Z_AttributeElement *element;
242         element = t->attributes->attributes[of];
243         if (element->attributeSet)
244         {
245             oident *attrset;
246             attrset = oid_getentbyoid (element->attributeSet);
247             attset_name = attrset->desc;
248         }
249         switch (element->which) 
250         {
251         case Z_AttributeValue_numeric:
252             attrStr (*element->attributeType,
253                      *element->value.numeric, ast, str);
254             yaz_log (loglevel, "%*.0s%s %s", depth, "", attset_name, str);
255             break;
256         case Z_AttributeValue_complex:
257             yaz_log (loglevel, "%*.0s%s attributeType=%d complex",
258                   depth, "", attset_name, *element->attributeType);
259             for (i = 0; i<element->value.complex->num_list; i++)
260             {
261                 if (element->value.complex->list[i]->which ==
262                     Z_StringOrNumeric_string)
263                     yaz_log (loglevel, "%*.0s  string: '%s'", depth, "",
264                              element->value.complex->list[i]->u.string);
265                 else if (element->value.complex->list[i]->which ==
266                          Z_StringOrNumeric_numeric)
267                     yaz_log (loglevel, "%*.0s  numeric: '%d'", depth, "",
268                              *element->value.complex->list[i]->u.numeric);
269             }
270             break;
271         default:
272             yaz_log (loglevel, "%.*s%s attribute unknown",
273                      depth, "", attset_name);
274         }
275     }
276 }
277
278 static char *complex_op_name(Z_Operator *op)
279 {
280     switch (op->which)
281     {
282         case Z_Operator_and:
283             return "and";
284         case Z_Operator_or:
285             return "or";
286         case Z_Operator_and_not:
287             return "and-not";
288         case Z_Operator_prox:
289             return "prox";
290         default:
291             return "unknown complex operator";
292     }
293 }
294
295 static char *prox_unit_name(Z_ProximityOperator *op)
296 {
297     if (op->which!=Z_ProximityOperator_known)
298          return "private";
299     switch(*op->u.known)
300     {
301         case Z_ProxUnit_character: return "character";
302         case Z_ProxUnit_word: return "word";
303         case Z_ProxUnit_sentence: return "sentence";
304         case Z_ProxUnit_paragraph: return "paragraph";
305         case Z_ProxUnit_section: return "section";
306         case Z_ProxUnit_chapter: return "chapter";
307         case Z_ProxUnit_document: return "document";
308         case Z_ProxUnit_element: return "element";
309         case Z_ProxUnit_subelement: return "subelement";
310         case Z_ProxUnit_elementType: return "elementType";
311         case Z_ProxUnit_byte: return "byte";
312         default: return "unknown";
313     }
314 }
315
316 static void zlog_structure (Z_RPNStructure *zs, int depth, 
317         enum oid_value ast, int loglevel)
318 {
319     if (zs->which == Z_RPNStructure_complex)
320     {
321         Z_Operator *op = zs->u.complex->roperator;
322         switch (op->which)
323         {
324         case Z_Operator_and:
325         case Z_Operator_or:
326         case Z_Operator_and_not:
327             yaz_log (loglevel, "%*.0s %s", depth, "", complex_op_name(op) );
328             break;
329         case Z_Operator_prox:
330             yaz_log (loglevel, "%*.0s prox excl=%s dist=%d order=%s "
331                      "rel=%s unit=%s",
332                      depth, "", op->u.prox->exclusion ?
333                      (*op->u.prox->exclusion ? "T" : "F") : "N", 
334                      *op->u.prox->distance,
335                      *op->u.prox->ordered ? "T" : "F",
336                      relToStr(*op->u.prox->relationType),
337                      prox_unit_name(op->u.prox) );
338             break;
339         default:
340             yaz_log (loglevel, "%*.0s unknown complex", depth, "");
341             return;
342         }
343         zlog_structure (zs->u.complex->s1, depth+2, ast, loglevel);
344         zlog_structure (zs->u.complex->s2, depth+2, ast, loglevel);
345     } 
346     else if (zs->which == Z_RPNStructure_simple)
347     {
348         if (zs->u.simple->which == Z_Operand_APT)
349         {
350             Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
351
352             switch (zapt->term->which)
353             {
354             case Z_Term_general:
355                 yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
356                          zapt->term->u.general->len,
357                          zapt->term->u.general->buf);
358                 break;
359             case Z_Term_characterString:
360                 yaz_log (loglevel, "%*.0s term '%s' (string)", depth, "",
361                          zapt->term->u.characterString);
362                 break;
363             case Z_Term_numeric:
364                 yaz_log (loglevel, "%*.0s term '%d' (numeric)", depth, "",
365                          *zapt->term->u.numeric);
366                 break;
367             case Z_Term_null:
368                 yaz_log (loglevel, "%*.0s term (null)", depth, "");
369                 break;
370             default:
371                 yaz_log (loglevel, "%*.0s term (not general)", depth, "");
372             }
373             zlog_attributes (zapt, depth+2, ast, loglevel);
374         }
375         else if (zs->u.simple->which == Z_Operand_resultSetId)
376         {
377             yaz_log (loglevel, "%*.0s set '%s'", depth, "",
378                      zs->u.simple->u.resultSetId);
379         }
380         else
381             yaz_log (loglevel, "%*.0s unknown simple structure", depth, "");
382     }
383     else
384         yaz_log (loglevel, "%*.0s unknown structure", depth, "");
385 }
386
387 static void wrbuf_structure (WRBUF b, Z_RPNStructure *zs, enum oid_value ast)
388 {
389     int i;
390     if (zs->which == Z_RPNStructure_complex)
391     {
392         Z_Operator *op = zs->u.complex->roperator;
393         wrbuf_printf(b, "@%s ", complex_op_name(op) );
394         if (op->which== Z_Operator_prox)
395         {
396             wrbuf_printf(b, "(excl=%s dist=%d order=%s "
397                      "rel=%s unit=%s) ",
398                      op->u.prox->exclusion ?
399                      (*op->u.prox->exclusion ? "T" : "F") : "N", 
400                      *op->u.prox->distance,
401                      *op->u.prox->ordered ? "T" : "F",
402                      relToStr(*op->u.prox->relationType),
403                      prox_unit_name(op->u.prox) );
404         }
405         wrbuf_structure (b,zs->u.complex->s1, ast);
406         wrbuf_structure (b,zs->u.complex->s2, ast);
407     }
408     else if (zs->which == Z_RPNStructure_simple)
409     {
410         if (zs->u.simple->which == Z_Operand_APT)
411         {
412             Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
413             int num_attributes = zapt->attributes->num_attributes;
414             for (i=0;i<num_attributes;i++)
415                  wrbuf_attr(b,zapt->attributes->attributes[i]);
416
417             switch (zapt->term->which)
418             {
419             case Z_Term_general:
420                 wrbuf_printf(b, "'%.*s' ",
421                          zapt->term->u.general->len,
422                          zapt->term->u.general->buf);
423                 break;
424             case Z_Term_characterString:
425                 wrbuf_printf(b, "\"%s\" ", zapt->term->u.characterString);
426                 break;
427             case Z_Term_numeric:
428                 wrbuf_printf(b, "%d ", *zapt->term->u.numeric);
429                 break;
430             case Z_Term_null:
431                 wrbuf_printf(b, "(null) ");
432                 break;
433             default:
434                 wrbuf_printf(b, "(unknown term type %d) ", zapt->term->which);
435             }
436         }
437         else if (zs->u.simple->which == Z_Operand_resultSetId)
438         {
439             wrbuf_printf(b, "@set '%s' ", zs->u.simple->u.resultSetId);
440         }
441         else
442             wrbuf_printf (b, "(unknown simple structure)");
443     }
444     else
445         wrbuf_puts(b, "(unknown structure)");
446 }
447
448 void log_rpn_query_level (int loglevel, Z_RPNQuery *rpn)
449 {
450     oident *attrset;
451     enum oid_value ast;
452     
453     attrset = oid_getentbyoid (rpn->attributeSetId);
454     if (attrset)
455     {
456         ast = attrset->value;
457         yaz_log (loglevel, "RPN query. Type: %s", attrset->desc);
458     } 
459     else
460     {
461         ast = VAL_NONE;
462         yaz_log (loglevel, "RPN query. Unknown type");
463     }
464     zlog_structure (rpn->RPNStructure, 0, ast, loglevel);
465 }
466
467 static void wrbuf_rpn_query(WRBUF b, Z_RPNQuery *rpn)
468 {
469     oident *attrset;
470     enum oid_value ast;
471     
472     attrset = oid_getentbyoid (rpn->attributeSetId);
473     if (attrset)
474     {
475         ast = attrset->value;
476         wrbuf_printf(b, " @attrset %s ", attrset->desc);
477     } 
478     else
479     {
480         ast = VAL_NONE;
481         wrbuf_printf (b, "Unknown:");
482     }
483     wrbuf_structure (b,rpn->RPNStructure, ast);
484
485 }
486
487 void log_rpn_query (Z_RPNQuery *rpn)
488 {
489     log_rpn_query_level(LOG_LOG, rpn);
490 }
491
492 void log_scan_term_level (int loglevel, 
493          Z_AttributesPlusTerm *zapt, oid_value ast)
494 {
495     int depth = 0;
496     if (!loglevel)
497         return;
498     if (zapt->term->which == Z_Term_general) 
499     {
500         yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
501                  zapt->term->u.general->len, zapt->term->u.general->buf);
502     }
503     else
504         yaz_log (loglevel, "%*.0s term (not general)", depth, "");
505     zlog_attributes (zapt, depth+2, ast, loglevel);
506 }
507
508 void log_scan_term (Z_AttributesPlusTerm *zapt, oid_value ast)
509 {
510     log_scan_term_level (LOG_LOG, zapt, ast);
511 }
512
513 void wrbuf_scan_term(WRBUF b, Z_AttributesPlusTerm *zapt, oid_value ast)
514 {
515     int num_attributes = zapt->attributes->num_attributes;
516     int i;
517     for (i=0;i<num_attributes;i++)
518         wrbuf_attr(b,zapt->attributes->attributes[i]);
519     if (zapt->term->which == Z_Term_general)
520     {
521         wrbuf_printf (b, "'%.*s' ", 
522            zapt->term->u.general->len, 
523            zapt->term->u.general->buf);
524     }
525     else
526         wrbuf_printf (b, "(not a general term)");
527 }
528
529 void yaz_log_zquery_level (int loglevel, Z_Query *q)
530 {
531     if (!loglevel)
532         return; 
533     switch (q->which)
534     {
535     case Z_Query_type_1: case Z_Query_type_101:
536         log_rpn_query_level (loglevel, q->u.type_1);
537         break;
538     case Z_Query_type_2:
539         yaz_log(loglevel, "CCL: %.*s", q->u.type_2->len, q->u.type_2->buf);
540         break;
541     case Z_Query_type_100:
542         yaz_log(loglevel, "Z39.58: %.*s", q->u.type_100->len,
543                 q->u.type_100->buf);
544         break;
545     case Z_Query_type_104:
546         if (q->u.type_104->which == Z_External_CQL)
547             yaz_log (loglevel, "CQL: %s", q->u.type_104->u.cql);
548     }
549 }
550
551 void yaz_log_zquery (Z_Query *q)
552 {
553     yaz_log_zquery_level(LOG_LOG,q);
554 }
555
556 void wrbuf_put_zquery(WRBUF b, Z_Query *q)
557 {
558     assert(q);
559     assert(b);
560     switch (q->which)
561     {
562         case Z_Query_type_1: 
563         case Z_Query_type_101:
564             wrbuf_printf(b,"Z:");
565             wrbuf_rpn_query(b,q->u.type_1);
566             break;
567         case Z_Query_type_2:
568             wrbuf_printf(b, "CCL: %.*s", q->u.type_2->len, q->u.type_2->buf);
569             break;
570         case Z_Query_type_100:
571             wrbuf_printf(b, "Z39.58: %.*s", q->u.type_100->len,
572                     q->u.type_100->buf);
573             break;
574         case Z_Query_type_104:
575             if (q->u.type_104->which == Z_External_CQL)
576                 wrbuf_printf(b, "CQL: %s", q->u.type_104->u.cql);
577             else
578                 wrbuf_printf(b,"Unknown type 104 query %d", q->u.type_104->which);
579     }
580 }
581
582 void wrbuf_diags(WRBUF b, int num_diagnostics,Z_DiagRec **diags)
583 {
584     /* we only dump the first diag - that keeps the log cleaner. */
585     wrbuf_printf(b," ERROR ");
586     if (diags[0]->which != Z_DiagRec_defaultFormat)
587         wrbuf_printf(b,"(diag not in default format?)");
588     else
589     {
590         Z_DefaultDiagFormat *e=diags[0]->u.defaultFormat;
591         if (e->condition)
592             wrbuf_printf(b, "%d ",*e->condition);
593         else
594             wrbuf_printf(b, "?? ");
595         if ((e->which==Z_DefaultDiagFormat_v2Addinfo) && (e->u.v2Addinfo))
596             wrbuf_printf(b,"%s ",e->u.v2Addinfo);
597         else if ((e->which==Z_DefaultDiagFormat_v3Addinfo) && (e->u.v3Addinfo))
598             wrbuf_printf(b,"%s ",e->u.v3Addinfo);
599     }
600 }