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