Modify wrbuf_put_zquery and wrbuf_scan_term so the generated
[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.6 2004-11-17 00:18:54 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
38 static void attrStr (int type, int value, enum oid_value ast, char *str)
39 {
40     const char *rstr;
41     *str = '\0';
42     switch (ast)
43     {
44     case VAL_BIB1:
45     case VAL_EXP1:
46     case VAL_GILS:
47         switch (type)
48         {
49         case 1:
50             sprintf (str, "use");
51             break;
52         case 2:
53             rstr = relToStr(value);
54             if (rstr)
55                 sprintf (str, "relation=%s", rstr);
56             else
57                 sprintf (str, "relation=%d", value);
58             break;
59         case 3:
60             switch (value)
61             {
62             case 1:
63                 sprintf (str, "position=First in field");
64                 break;
65             case 2:
66                 sprintf (str, "position=First in any subfield");
67                 break;
68             case 3:
69                 sprintf (str, "position=Any position in field");
70                 break;
71             default:
72                 sprintf (str, "position");
73             }
74             break;
75         case 4:
76             switch (value)
77             {
78             case 1:
79                 sprintf (str, "structure=Phrase");
80                 break;
81             case 2:
82                 sprintf (str, "structure=Word");
83                 break;
84             case 3:
85                 sprintf (str, "structure=Key");
86                 break;
87             case 4:
88                 sprintf (str, "structure=Year");
89                 break;
90             case 5:
91                 sprintf (str, "structure=Date");
92                 break;
93             case 6:
94                 sprintf (str, "structure=Word list");
95                 break;
96             case 100:
97                 sprintf (str, "structure=Date (un)");
98                 break;
99             case 101:
100                 sprintf (str, "structure=Name (norm)");
101                 break;
102             case 102:
103                 sprintf (str, "structure=Name (un)");
104                 break;
105             case 103:
106                 sprintf (str, "structure=Structure");
107                 break;
108             case 104:
109                 sprintf (str, "structure=urx");
110                 break;
111             case 105:
112                 sprintf (str, "structure=free-form-text");
113                 break;
114             case 106:
115                 sprintf (str, "structure=document-text");
116                 break;
117             case 107:
118                 sprintf (str, "structure=local-number");
119                 break;
120             case 108:
121                 sprintf (str, "structure=string");
122                 break;
123             case 109:
124                 sprintf (str, "structure=numeric string");
125                 break;
126             default:
127                 sprintf (str, "structure");
128             }
129             break;
130         case 5:
131             switch (value)
132             {
133             case 1:
134                 sprintf (str, "truncation=Right");
135                 break;
136             case 2:
137                 sprintf (str, "truncation=Left");
138                 break;
139             case 3:
140                 sprintf (str, "truncation=Left&right");
141                 break;
142             case 100:
143                 sprintf (str, "truncation=Do not truncate");
144                 break;
145             case 101:
146                 sprintf (str, "truncation=Process #");
147                 break;
148             case 102:
149                 sprintf (str, "truncation=re-1");
150                 break;
151             case 103:
152                 sprintf (str, "truncation=re-2");
153                 break;
154             case 104:
155                 sprintf (str, "truncation=CCL");
156                 break;
157             default:
158                 sprintf (str, "truncation");
159             }
160             break;
161         case 6:
162             switch (value)
163             {
164             case 1:
165                 sprintf (str, "completeness=Incomplete subfield");
166                 break;
167             case 2:
168                 sprintf (str, "completeness=Complete subfield");
169                 break;
170             case 3:
171                 sprintf (str, "completeness=Complete field");
172                 break;
173             default:
174                 sprintf (str, "completeness");
175             }
176             break;
177         }
178         break;
179     default:
180         break;
181     }
182     if (*str)
183         sprintf (str + strlen(str), " (%d=%d)", type, value);
184     else
185         sprintf (str, "%d=%d", type, value);
186 }
187
188 static void wrbuf_term(WRBUF b, const char *term, int len)
189 {
190     int i;
191     for (i = 0; i < len; i++)
192         if (strchr(" \"{", term[i]))
193             break;
194     if (i == len && i)
195         wrbuf_printf(b, "%.*s ", len, term);
196     else
197     {
198         wrbuf_putc(b, '"');
199         for (i = 0; i<len; i++)
200         {
201             if (term[i] == '"')
202                 wrbuf_putc(b, '\\');
203             wrbuf_putc(b, term[i]);
204         }
205         wrbuf_printf(b, "\" ");
206     }
207 }
208
209 static void wrbuf_attr(WRBUF b, Z_AttributeElement *element)
210 {
211     int i;
212     char *setname="";
213     char *sep = ""; /* optional space after attrset name */
214     if (element->attributeSet)
215     {
216         oident *attrset;
217         attrset = oid_getentbyoid (element->attributeSet);
218         setname = attrset->desc;
219         sep = " ";
220     }
221     switch (element->which) 
222     {
223     case Z_AttributeValue_numeric:
224         wrbuf_printf(b,"@attr %s%s%d=%d ", setname, sep,
225                      *element->attributeType, *element->value.numeric);
226         break;
227     case Z_AttributeValue_complex:
228         wrbuf_printf(b,"@attr %s%s\"%d=", setname, sep,
229                      *element->attributeType);
230         for (i = 0; i<element->value.complex->num_list; i++)
231         {
232             if (i)
233                 wrbuf_printf(b,",");
234             if (element->value.complex->list[i]->which ==
235                 Z_StringOrNumeric_string)
236                 wrbuf_printf (b, "%s",
237                               element->value.complex->list[i]->u.string);
238             else if (element->value.complex->list[i]->which ==
239                      Z_StringOrNumeric_numeric)
240                 wrbuf_printf (b, "%d", 
241                               *element->value.complex->list[i]->u.numeric);
242         }
243         wrbuf_printf(b, "\" ");
244         break;
245     default:
246         wrbuf_printf (b, "@attr 1=unknown ");
247     }
248 }
249
250 /*
251  * zlog_attributes: print attributes of term
252  */
253 static void zlog_attributes (Z_AttributesPlusTerm *t, int depth,
254                              enum oid_value ast, int loglevel)
255 {
256     int of, i;
257     char str[80];
258     int num_attributes = t->attributes->num_attributes;
259     
260     for (of = 0; of < num_attributes; of++)
261     {
262         const char *attset_name = "";
263         Z_AttributeElement *element;
264         element = t->attributes->attributes[of];
265         if (element->attributeSet)
266         {
267             oident *attrset;
268             attrset = oid_getentbyoid (element->attributeSet);
269             attset_name = attrset->desc;
270         }
271         switch (element->which) 
272         {
273         case Z_AttributeValue_numeric:
274             attrStr (*element->attributeType,
275                      *element->value.numeric, ast, str);
276             yaz_log (loglevel, "%*.0s%s %s", depth, "", attset_name, str);
277             break;
278         case Z_AttributeValue_complex:
279             yaz_log (loglevel, "%*.0s%s attributeType=%d complex",
280                   depth, "", attset_name, *element->attributeType);
281             for (i = 0; i<element->value.complex->num_list; i++)
282             {
283                 if (element->value.complex->list[i]->which ==
284                     Z_StringOrNumeric_string)
285                     yaz_log (loglevel, "%*.0s  string: '%s'", depth, "",
286                              element->value.complex->list[i]->u.string);
287                 else if (element->value.complex->list[i]->which ==
288                          Z_StringOrNumeric_numeric)
289                     yaz_log (loglevel, "%*.0s  numeric: '%d'", depth, "",
290                              *element->value.complex->list[i]->u.numeric);
291             }
292             break;
293         default:
294             yaz_log (loglevel, "%.*s%s attribute unknown",
295                      depth, "", attset_name);
296         }
297     }
298 }
299
300 static char *complex_op_name(Z_Operator *op)
301 {
302     switch (op->which)
303     {
304     case Z_Operator_and:
305         return "and";
306     case Z_Operator_or:
307         return "or";
308     case Z_Operator_and_not:
309         return "not";
310     case Z_Operator_prox:
311         return "prox";
312     default:
313         return "unknown complex operator";
314     }
315 }
316
317 static char *prox_unit_name(Z_ProximityOperator *op)
318 {
319     if (op->which!=Z_ProximityOperator_known)
320          return "private";
321     switch(*op->u.known)
322     {
323         case Z_ProxUnit_character: return "character";
324         case Z_ProxUnit_word: return "word";
325         case Z_ProxUnit_sentence: return "sentence";
326         case Z_ProxUnit_paragraph: return "paragraph";
327         case Z_ProxUnit_section: return "section";
328         case Z_ProxUnit_chapter: return "chapter";
329         case Z_ProxUnit_document: return "document";
330         case Z_ProxUnit_element: return "element";
331         case Z_ProxUnit_subelement: return "subelement";
332         case Z_ProxUnit_elementType: return "elementType";
333         case Z_ProxUnit_byte: return "byte";
334         default: return "unknown";
335     }
336 }
337
338 static void zlog_structure (Z_RPNStructure *zs, int depth, 
339         enum oid_value ast, int loglevel)
340 {
341     if (zs->which == Z_RPNStructure_complex)
342     {
343         Z_Operator *op = zs->u.complex->roperator;
344         switch (op->which)
345         {
346         case Z_Operator_and:
347         case Z_Operator_or:
348         case Z_Operator_and_not:
349             yaz_log (loglevel, "%*.0s %s", depth, "", complex_op_name(op) );
350             break;
351         case Z_Operator_prox:
352             yaz_log (loglevel, "%*.0s prox excl=%s dist=%d order=%s "
353                      "rel=%s unit=%s",
354                      depth, "", op->u.prox->exclusion ?
355                      (*op->u.prox->exclusion ? "T" : "F") : "N", 
356                      *op->u.prox->distance,
357                      *op->u.prox->ordered ? "T" : "F",
358                      relToStr(*op->u.prox->relationType),
359                      prox_unit_name(op->u.prox) );
360             break;
361         default:
362             yaz_log (loglevel, "%*.0s unknown complex", depth, "");
363             return;
364         }
365         zlog_structure (zs->u.complex->s1, depth+2, ast, loglevel);
366         zlog_structure (zs->u.complex->s2, depth+2, ast, loglevel);
367     } 
368     else if (zs->which == Z_RPNStructure_simple)
369     {
370         if (zs->u.simple->which == Z_Operand_APT)
371         {
372             Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
373
374             switch (zapt->term->which)
375             {
376             case Z_Term_general:
377                 yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
378                          zapt->term->u.general->len,
379                          zapt->term->u.general->buf);
380                 break;
381             case Z_Term_characterString:
382                 yaz_log (loglevel, "%*.0s term '%s' (string)", depth, "",
383                          zapt->term->u.characterString);
384                 break;
385             case Z_Term_numeric:
386                 yaz_log (loglevel, "%*.0s term '%d' (numeric)", depth, "",
387                          *zapt->term->u.numeric);
388                 break;
389             case Z_Term_null:
390                 yaz_log (loglevel, "%*.0s term (null)", depth, "");
391                 break;
392             default:
393                 yaz_log (loglevel, "%*.0s term (not general)", depth, "");
394             }
395             zlog_attributes (zapt, depth+2, ast, loglevel);
396         }
397         else if (zs->u.simple->which == Z_Operand_resultSetId)
398         {
399             yaz_log (loglevel, "%*.0s set '%s'", depth, "",
400                      zs->u.simple->u.resultSetId);
401         }
402         else
403             yaz_log (loglevel, "%*.0s unknown simple structure", depth, "");
404     }
405     else
406         yaz_log (loglevel, "%*.0s unknown structure", depth, "");
407 }
408
409 static void wrbuf_apt(WRBUF b, Z_AttributesPlusTerm *zapt)
410 {
411     int num_attributes = zapt->attributes->num_attributes;
412     int i;
413     for (i = 0; i<num_attributes; i++)
414         wrbuf_attr(b,zapt->attributes->attributes[i]);
415     
416     switch (zapt->term->which)
417     {
418     case Z_Term_general:
419         wrbuf_term(b, zapt->term->u.general->buf,
420                    zapt->term->u.general->len);
421         break;
422     case Z_Term_characterString:
423         wrbuf_printf(b, "@term string ");
424         wrbuf_term (b, zapt->term->u.characterString,
425                     strlen(zapt->term->u.characterString));
426         break;
427     case Z_Term_numeric:
428         wrbuf_printf(b, "@term numeric %d ", *zapt->term->u.numeric);
429         break;
430     case Z_Term_null:
431         wrbuf_printf(b, "@term null x");
432         break;
433     default:
434         wrbuf_printf(b, "@term null unknown%d ", zapt->term->which);
435     }
436 }
437     
438 static void wrbuf_structure (WRBUF b, Z_RPNStructure *zs, enum oid_value ast)
439 {
440     int i;
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(LOG_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 (LOG_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(LOG_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,"Z:");
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 }