Fixed 523: PQF parser does not properly diagnose @prox syntax errors.
[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.14 2006-01-20 10:34:51 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 /*
189  * zlog_attributes: print attributes of term
190  */
191 static void zlog_attributes (Z_AttributesPlusTerm *t, int depth,
192                              enum oid_value ast, int loglevel)
193 {
194     int of, i;
195     char str[80];
196     int num_attributes = t->attributes->num_attributes;
197     
198     for (of = 0; of < num_attributes; of++)
199     {
200         const char *attset_name = "";
201         Z_AttributeElement *element;
202         element = t->attributes->attributes[of];
203         if (element->attributeSet)
204         {
205             oident *attrset;
206             attrset = oid_getentbyoid (element->attributeSet);
207             attset_name = attrset->desc;
208         }
209         switch (element->which) 
210         {
211         case Z_AttributeValue_numeric:
212             attrStr (*element->attributeType,
213                      *element->value.numeric, ast, str);
214             yaz_log (loglevel, "%*.0s%s %s", depth, "", attset_name, str);
215             break;
216         case Z_AttributeValue_complex:
217             yaz_log (loglevel, "%*.0s%s attributeType=%d complex",
218                   depth, "", attset_name, *element->attributeType);
219             for (i = 0; i<element->value.complex->num_list; i++)
220             {
221                 if (element->value.complex->list[i]->which ==
222                     Z_StringOrNumeric_string)
223                     yaz_log (loglevel, "%*.0s  string: '%s'", depth, "",
224                              element->value.complex->list[i]->u.string);
225                 else if (element->value.complex->list[i]->which ==
226                          Z_StringOrNumeric_numeric)
227                     yaz_log (loglevel, "%*.0s  numeric: '%d'", depth, "",
228                              *element->value.complex->list[i]->u.numeric);
229             }
230             break;
231         default:
232             yaz_log (loglevel, "%.*s%s attribute unknown",
233                      depth, "", attset_name);
234         }
235     }
236 }
237
238 static char *complex_op_name(Z_Operator *op)
239 {
240     switch (op->which)
241     {
242     case Z_Operator_and:
243         return "and";
244     case Z_Operator_or:
245         return "or";
246     case Z_Operator_and_not:
247         return "not";
248     case Z_Operator_prox:
249         return "prox";
250     default:
251         return "unknown complex operator";
252     }
253 }
254
255 static char *prox_unit_name(Z_ProximityOperator *op)
256 {
257     if (op->which!=Z_ProximityOperator_known)
258          return "private";
259     switch(*op->u.known)
260     {
261         case Z_ProxUnit_character: return "character";
262         case Z_ProxUnit_word: return "word";
263         case Z_ProxUnit_sentence: return "sentence";
264         case Z_ProxUnit_paragraph: return "paragraph";
265         case Z_ProxUnit_section: return "section";
266         case Z_ProxUnit_chapter: return "chapter";
267         case Z_ProxUnit_document: return "document";
268         case Z_ProxUnit_element: return "element";
269         case Z_ProxUnit_subelement: return "subelement";
270         case Z_ProxUnit_elementType: return "elementType";
271         case Z_ProxUnit_byte: return "byte";
272         default: return "unknown";
273     }
274 }
275
276 static void zlog_structure (Z_RPNStructure *zs, int depth, 
277         enum oid_value ast, int loglevel)
278 {
279     if (zs->which == Z_RPNStructure_complex)
280     {
281         Z_Operator *op = zs->u.complex->roperator;
282         switch (op->which)
283         {
284         case Z_Operator_and:
285         case Z_Operator_or:
286         case Z_Operator_and_not:
287             yaz_log (loglevel, "%*.0s %s", depth, "", complex_op_name(op) );
288             break;
289         case Z_Operator_prox:
290             yaz_log (loglevel, "%*.0s prox excl=%s dist=%d order=%s "
291                      "rel=%s unit=%s",
292                      depth, "", op->u.prox->exclusion ?
293                      (*op->u.prox->exclusion ? "T" : "F") : "N", 
294                      *op->u.prox->distance,
295                      *op->u.prox->ordered ? "T" : "F",
296                      relToStr(*op->u.prox->relationType),
297                      prox_unit_name(op->u.prox) );
298             break;
299         default:
300             yaz_log (loglevel, "%*.0s unknown complex", depth, "");
301             return;
302         }
303         zlog_structure (zs->u.complex->s1, depth+2, ast, loglevel);
304         zlog_structure (zs->u.complex->s2, depth+2, ast, loglevel);
305     } 
306     else if (zs->which == Z_RPNStructure_simple)
307     {
308         if (zs->u.simple->which == Z_Operand_APT)
309         {
310             Z_AttributesPlusTerm *zapt = zs->u.simple->u.attributesPlusTerm;
311
312             switch (zapt->term->which)
313             {
314             case Z_Term_general:
315                 yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
316                          zapt->term->u.general->len,
317                          zapt->term->u.general->buf);
318                 break;
319             case Z_Term_characterString:
320                 yaz_log (loglevel, "%*.0s term '%s' (string)", depth, "",
321                          zapt->term->u.characterString);
322                 break;
323             case Z_Term_numeric:
324                 yaz_log (loglevel, "%*.0s term '%d' (numeric)", depth, "",
325                          *zapt->term->u.numeric);
326                 break;
327             case Z_Term_null:
328                 yaz_log (loglevel, "%*.0s term (null)", depth, "");
329                 break;
330             default:
331                 yaz_log (loglevel, "%*.0s term (not general)", depth, "");
332             }
333             zlog_attributes (zapt, depth+2, ast, loglevel);
334         }
335         else if (zs->u.simple->which == Z_Operand_resultSetId)
336         {
337             yaz_log (loglevel, "%*.0s set '%s'", depth, "",
338                      zs->u.simple->u.resultSetId);
339         }
340         else
341             yaz_log (loglevel, "%*.0s unknown simple structure", depth, "");
342     }
343     else
344         yaz_log (loglevel, "%*.0s unknown structure", depth, "");
345 }
346
347 void log_rpn_query_level (int loglevel, Z_RPNQuery *rpn)
348 {
349     oident *attrset;
350     enum oid_value ast;
351     
352     attrset = oid_getentbyoid (rpn->attributeSetId);
353     if (attrset)
354     {
355         ast = attrset->value;
356         yaz_log (loglevel, "RPN query. Type: %s", attrset->desc);
357     } 
358     else
359     {
360         ast = VAL_NONE;
361         yaz_log (loglevel, "RPN query. Unknown type");
362     }
363     zlog_structure (rpn->RPNStructure, 0, ast, loglevel);
364 }
365
366 void log_rpn_query(Z_RPNQuery *rpn)
367 {
368     log_rpn_query_level(YLOG_LOG, rpn);
369 }
370
371 void log_scan_term_level(int loglevel, 
372                          Z_AttributesPlusTerm *zapt, oid_value ast)
373 {
374     int depth = 0;
375     if (!loglevel)
376         return;
377     if (zapt->term->which == Z_Term_general) 
378     {
379         yaz_log (loglevel, "%*.0s term '%.*s' (general)", depth, "",
380                  zapt->term->u.general->len, zapt->term->u.general->buf);
381     }
382     else
383         yaz_log (loglevel, "%*.0s term (not general)", depth, "");
384     zlog_attributes (zapt, depth+2, ast, loglevel);
385 }
386
387 void log_scan_term(Z_AttributesPlusTerm *zapt, oid_value ast)
388 {
389     log_scan_term_level (YLOG_LOG, zapt, ast);
390 }
391
392 void yaz_log_zquery_level (int loglevel, Z_Query *q)
393 {
394     if (!loglevel)
395         return; 
396     switch (q->which)
397     {
398     case Z_Query_type_1: case Z_Query_type_101:
399         log_rpn_query_level (loglevel, q->u.type_1);
400         break;
401     case Z_Query_type_2:
402         yaz_log(loglevel, "CCL: %.*s", q->u.type_2->len, q->u.type_2->buf);
403         break;
404     case Z_Query_type_100:
405         yaz_log(loglevel, "Z39.58: %.*s", q->u.type_100->len,
406                 q->u.type_100->buf);
407         break;
408     case Z_Query_type_104:
409         if (q->u.type_104->which == Z_External_CQL)
410             yaz_log (loglevel, "CQL: %s", q->u.type_104->u.cql);
411     }
412 }
413
414 void yaz_log_zquery (Z_Query *q)
415 {
416     yaz_log_zquery_level(YLOG_LOG, q);
417 }
418
419 void wrbuf_diags(WRBUF b, int num_diagnostics,Z_DiagRec **diags)
420 {
421     /* we only dump the first diag - that keeps the log cleaner. */
422     wrbuf_printf(b," ERROR ");
423     if (diags[0]->which != Z_DiagRec_defaultFormat)
424         wrbuf_printf(b,"(diag not in default format?)");
425     else
426     {
427         Z_DefaultDiagFormat *e=diags[0]->u.defaultFormat;
428         if (e->condition)
429             wrbuf_printf(b, "%d ",*e->condition);
430         else
431             wrbuf_printf(b, "?? ");
432         if ((e->which==Z_DefaultDiagFormat_v2Addinfo) && (e->u.v2Addinfo))
433             wrbuf_printf(b,"%s ",e->u.v2Addinfo);
434         else if ((e->which==Z_DefaultDiagFormat_v3Addinfo) && (e->u.v3Addinfo))
435             wrbuf_printf(b,"%s ",e->u.v3Addinfo);
436     }
437 }
438 /*
439  * Local variables:
440  * c-basic-offset: 4
441  * indent-tabs-mode: nil
442  * End:
443  * vim: shiftwidth=4 tabstop=8 expandtab
444  */
445