Minor change in definition of Z_TargetInfo. Furhter work on Explain
[yaz-moved-to-github.git] / retrieval / d1_expout.c
1 /*
2  * Copyright (c) 1995-1998, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_expout.c,v $
7  * Revision 1.11  1998-04-02 08:27:37  adam
8  * Minor change in definition of Z_TargetInfo. Furhter work on Explain
9  * schema - added AttributeDetails.
10  *
11  * Revision 1.10  1998/03/31 15:13:20  adam
12  * Development towards compiled ASN.1.
13  *
14  * Revision 1.9  1998/03/05 08:07:58  adam
15  * Make data1 to EXPLAIN ignore local tags in root.
16  *
17  * Revision 1.8  1998/02/11 11:53:35  adam
18  * Changed code so that it compiles as C++.
19  *
20  * Revision 1.7  1997/12/09 16:18:16  adam
21  * Work on EXPLAIN schema. First implementation of sub-schema facility
22  * in the *.abs files.
23  *
24  * Revision 1.6  1997/11/24 11:33:56  adam
25  * Using function odr_nullval() instead of global ODR_NULLVAL when
26  * appropriate.
27  *
28  * Revision 1.5  1997/11/19 10:30:06  adam
29  * More explain work.
30  *
31  * Revision 1.4  1997/11/18 09:51:08  adam
32  * Removed element num_children from data1_node. Minor changes in
33  * data1 to Explain.
34  *
35  * Revision 1.3  1997/09/17 12:10:36  adam
36  * YAZ version 1.4.
37  *
38  * Revision 1.2  1995/12/14 16:28:30  quinn
39  * More explain stuff.
40  *
41  * Revision 1.1  1995/12/14  11:09:51  quinn
42  * Work on Explain
43  *
44  *
45  */
46
47 #include <assert.h>
48 #include <string.h>
49 #include <stdlib.h>
50
51 #include <log.h>
52 #include <proto.h>
53 #include <data1.h>
54
55 typedef struct {
56     data1_handle dh;
57     ODR o;
58     int select;
59
60     bool_t *false_value;
61     bool_t *true_value;
62 } ExpHandle;
63
64 static int is_numeric_tag (ExpHandle *eh, data1_node *c)
65 {
66     if (!c || c->which != DATA1N_tag)
67         return 0;
68     if (!c->u.tag.element)
69     {
70         logf(LOG_WARN, "Tag %s is local", c->u.tag.tag);
71         return 0;
72     }
73     if (c->u.tag.element->tag->which != DATA1T_numeric)
74     {
75         logf(LOG_WARN, "Tag %s is not numeric", c->u.tag.tag);
76         return 0;
77     }
78     if (eh->select && !c->u.tag.node_selected)
79         return 0;
80     return c->u.tag.element->tag->value.numeric;
81 }
82
83 static int is_data_tag (ExpHandle *eh, data1_node *c)
84 {
85     if (!c || c->which != DATA1N_data)
86         return 0;
87     if (eh->select && !c->u.tag.node_selected)
88         return 0;
89     return 1;
90 }
91
92 static int *f_integer(ExpHandle *eh, data1_node *c)
93 {
94     int *r;
95     char intbuf[64];
96
97     c = c->child;
98     if (!is_data_tag (eh, c) || c->u.data.len > 63)
99         return 0;
100     r = (int *)odr_malloc(eh->o, sizeof(*r));
101     sprintf(intbuf, "%.*s", 63, c->u.data.data);
102     *r = atoi(intbuf);
103     return r;
104 }
105
106 static char *f_string(ExpHandle *eh, data1_node *c)
107 {
108     char *r;
109
110     c = c->child;
111     if (!is_data_tag (eh, c))
112         return 0;
113     r = (char *)odr_malloc(eh->o, c->u.data.len+1);
114     memcpy(r, c->u.data.data, c->u.data.len);
115     r[c->u.data.len] = '\0';
116     return r;
117 }
118
119 static bool_t *f_bool(ExpHandle *eh, data1_node *c)
120 {
121     bool_t *tf;
122     char intbuf[64];
123
124     c = c->child;
125     if (!is_data_tag (eh, c) || c->u.data.len > 63)
126         return 0;
127     tf = (int *)odr_malloc (eh->o, sizeof(*tf));
128     sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
129     *tf = atoi(intbuf);
130     return tf;
131 }
132
133 static Odr_oid *f_oid(ExpHandle *eh, data1_node *c, oid_class oclass)
134 {
135     char oidstr[64];
136     int oid_this[20];
137     oid_value value_for_this;
138
139     c = c->child;
140     if (!is_data_tag (eh, c) || c->u.data.len > 63)
141         return 0;
142     sprintf(oidstr, "%.*s", c->u.data.len, c->u.data.data);
143     value_for_this = oid_getvalbyname(oidstr);
144     if (value_for_this == VAL_NONE)
145         return NULL; /* fix */
146     else
147     {
148         struct oident ident;
149
150         ident.oclass = oclass;
151         ident.proto = PROTO_Z3950;
152         ident.value = value_for_this;
153         
154         oid_ent_to_oid (&ident, oid_this);
155     }
156     return odr_oiddup (eh->o, oid_this);
157 }
158
159 static Z_IntUnit *f_intunit(ExpHandle *eh, data1_node *c)
160 {
161     /* fix */
162     return 0;
163 }
164
165 static Z_HumanString *f_humstring(ExpHandle *eh, data1_node *c)
166 {
167     Z_HumanString *r;
168     Z_HumanStringUnit *u;
169
170     c = c->child;
171     if (!is_data_tag (eh, c))
172         return 0;
173     r = (Z_HumanString *)odr_malloc(eh->o, sizeof(*r));
174     r->num_strings = 1;
175     r->strings = (Z_HumanStringUnit **)odr_malloc(eh->o, sizeof(Z_HumanStringUnit*));
176     r->strings[0] = u = (Z_HumanStringUnit *)odr_malloc(eh->o, sizeof(*u));
177     u->language = 0;
178     u->text = (char *)odr_malloc(eh->o, c->u.data.len+1);
179     memcpy(u->text, c->u.data.data, c->u.data.len);
180     u->text[c->u.data.len] = '\0';
181     return r;
182 }
183
184 static Z_CommonInfo *f_commonInfo(ExpHandle *eh, data1_node *n)
185 {
186     Z_CommonInfo *res = (Z_CommonInfo *)odr_malloc(eh->o, sizeof(*res));
187     data1_node *c;
188
189     res->dateAdded = 0;
190     res->dateChanged = 0;
191     res->expiry = 0;
192     res->humanStringLanguage = 0;
193     res->otherInfo = 0;
194
195     for (c = n->child; c; c = c->next)
196     {
197         switch (is_numeric_tag (eh, c))
198         {
199             case 601: res->dateAdded = f_string(eh, c); break;
200             case 602: res->dateChanged = f_string(eh, c); break;
201             case 603: res->expiry = f_string(eh, c); break;
202             case 604: res->humanStringLanguage = f_string(eh, c); break;
203         }
204     }
205     return res;
206 }
207
208 Z_QueryTypeDetails *f_queryTypeDetails (ExpHandle *eh, data1_node *n)
209 {
210     /* fix */
211     return NULL;
212 }
213
214 Odr_oid **f_oid_seq (ExpHandle *eh, data1_node *n, int *num, oid_class oclass)
215 {
216     Odr_oid **res;
217     data1_node *c;
218     int i;
219
220     *num = 0;
221     for (c = n->child ; c; c = c->next)
222     {
223         if (is_numeric_tag (eh, c) != 1000)
224             continue;
225         ++(*num);
226     }
227     if (!*num)
228         return NULL;
229     res = (int **)odr_malloc (eh->o, sizeof(*res) * (*num));
230     for (c = n->child, i = 0 ; c; c = c->next)
231     {
232         if (is_numeric_tag (eh, c) != 1000)
233             continue;
234         res[i++] = f_oid (eh, c, oclass);
235     }
236     return res;
237 }
238     
239 char **f_string_seq (ExpHandle *eh, data1_node *n, int *num)
240 {
241     char **res;
242     data1_node *c;
243     int i;
244
245     *num = 0;
246     for (c = n->child ; c; c = c->next)
247     {
248         if (!is_numeric_tag (eh, c) != 1001)
249             continue;
250         ++(*num);
251     }
252     if (!*num)
253         return NULL;
254     res = (char **)odr_malloc (eh->o, sizeof(*res) * (*num));
255     for (c = n->child, i = 0 ; c; c = c->next)
256     {
257         if (!is_numeric_tag (eh, c) != 1001)
258             continue;
259         res[i++] = f_string (eh, c);
260     }
261     return res;
262 }
263
264 char **f_humstring_seq (ExpHandle *eh, data1_node *n, int *num)
265 {
266     /* fix */
267     return NULL;
268 }
269
270
271 Z_RpnCapabilities *f_rpnCapabilities (ExpHandle *eh, data1_node *c)
272 {
273     Z_RpnCapabilities *res = (Z_RpnCapabilities *)odr_malloc (eh->o, sizeof(*res));
274
275     res->num_operators = 0;
276     res->operators = NULL;
277     res->resultSetAsOperandSupported = eh->false_value;
278     res->restrictionOperandSupported = eh->false_value;
279     res->proximity = NULL;
280     /* fix */ /* 550 - 560 */
281     return res;
282 }
283
284 Z_QueryTypeDetails **f_queryTypesSupported (ExpHandle *eh, data1_node *c,
285                                             int *num)
286 {
287     data1_node *n;
288     Z_QueryTypeDetails **res;
289     int i;
290
291     *num = 0;
292     for (n = c->child; n; n = n->next)
293     {
294         if (is_numeric_tag(eh, n) != 519)
295             continue;
296         /* fix */ /* 518 and 520 */
297         (*num)++;
298     }
299     if (!*num)
300         return NULL;
301     res = (Z_QueryTypeDetails **)odr_malloc (eh->o, *num * sizeof(*res));
302     i = 0;
303     for (n = c->child; n; n = n->next)
304     {
305         if (is_numeric_tag(eh, n) == 519)
306         {
307             res[i] = (Z_QueryTypeDetails *)odr_malloc (eh->o, sizeof(**res));
308             res[i]->which = Z_QueryTypeDetails_rpn;
309             res[i]->u.rpn = f_rpnCapabilities (eh, n);
310             i++;
311         }
312         else
313             continue;
314         /* fix */ /* 518 and 520 */
315     }
316     return res;
317 }
318
319 static Z_AccessInfo *f_accessInfo(ExpHandle *eh, data1_node *n)
320 {
321     Z_AccessInfo *res = (Z_AccessInfo *)odr_malloc(eh->o, sizeof(*res));
322     data1_node *c;
323
324     res->num_queryTypesSupported = 0;
325     res->queryTypesSupported = 0;
326     res->num_diagnosticsSets = 0;
327     res->diagnosticsSets = 0;
328     res->num_attributeSetIds = 0;
329     res->attributeSetIds = 0;
330     res->num_schemas = 0;
331     res->schemas = 0;
332     res->num_recordSyntaxes = 0;
333     res->recordSyntaxes = 0;
334     res->num_resourceChallenges = 0;
335     res->resourceChallenges = 0;
336     res->restrictedAccess = 0;
337     res->costInfo = 0;
338     res->num_variantSets = 0;
339     res->variantSets = 0;
340     res->num_elementSetNames = 0;
341     res->elementSetNames = 0;
342     res->num_unitSystems = 0;
343     res->unitSystems = 0;
344
345     for (c = n->child; c; c = c->next)
346     {
347         switch (is_numeric_tag (eh, c))
348         {
349         case 501:
350             res->queryTypesSupported =
351                 f_queryTypesSupported (eh, c, &res->num_queryTypesSupported);
352             break;
353         case 503:
354             res->diagnosticsSets =
355                 f_oid_seq(eh, c, &res->num_diagnosticsSets, CLASS_DIAGSET);
356             break;
357         case 505:
358             res->attributeSetIds =
359                 f_oid_seq(eh, c, &res->num_attributeSetIds, CLASS_ATTSET);
360             break;
361         case 507:
362             res->schemas =
363                 f_oid_seq(eh, c, &res->num_schemas, CLASS_SCHEMA);
364             break;
365         case 509:
366             res->recordSyntaxes =
367                 f_oid_seq (eh, c, &res->num_recordSyntaxes, CLASS_RECSYN);
368             break;
369         case 511:
370             res->resourceChallenges =
371                 f_oid_seq (eh, c, &res->num_resourceChallenges, CLASS_RESFORM);
372             break;
373         case 513: res->restrictedAccess = NULL; break; /* fix */
374         case 514: res->costInfo = NULL; break; /* fix */
375         case 515:
376             res->variantSets =
377                 f_oid_seq (eh, c, &res->num_variantSets, CLASS_VARSET);
378             break;
379         case 516:
380             res->elementSetNames =
381                 f_string_seq (eh, c, &res->num_elementSetNames);
382             break;
383         case 517:
384             res->unitSystems = f_string_seq (eh, c, &res->num_unitSystems);
385             break;
386         }
387     }
388     return res;
389 }
390
391 static int *f_recordCount(ExpHandle *eh, data1_node *c, int *which)
392 {
393     int *r= (int *)odr_malloc(eh->o, sizeof(*r));
394     int *wp = which;
395     char intbuf[64];
396
397     c = c->child;
398     if (!is_numeric_tag (eh, c))
399         return 0;
400 #ifdef ASN_COMPILED
401     if (c->u.tag.element->tag->value.numeric == 210)
402         *wp = Z_DatabaseInfo_actualNumber;
403     else if (c->u.tag.element->tag->value.numeric == 211)
404         *wp = Z_DatabaseInfo_approxNumber;
405     else
406         return 0;
407 #else
408     if (c->u.tag.element->tag->value.numeric == 210)
409         *wp = Z_Exp_RecordCount_actualNumber;
410     else if (c->u.tag.element->tag->value.numeric == 211)
411         *wp = Z_Exp_RecordCount_approxNumber;
412     else
413         return 0;
414 #endif
415     if (!c->child || c->child->which != DATA1N_data)
416         return 0;
417     sprintf(intbuf, "%.*s", 63, c->child->u.data.data);
418     *r = atoi(intbuf);
419     return r;
420 }
421
422 static Z_ContactInfo *f_contactInfo(ExpHandle *eh, data1_node *n)
423 {
424     /* fix */
425     return 0;
426 }
427
428 static Z_DatabaseList *f_databaseList(ExpHandle *eh, data1_node *n)
429 {
430     data1_node *c;
431     Z_DatabaseList *res;
432     int i = 0;
433     
434     for (c = n->child; c; c = c->next)
435     {
436         if (!is_numeric_tag (eh, c) != 102) 
437             continue;
438         ++i;
439     }
440     if (!i)
441         return NULL;
442
443     res = (Z_DatabaseList *)odr_malloc (eh->o, sizeof(*res));
444     
445     res->num_databases = i;
446     res->databases = (char **)odr_malloc (eh->o, sizeof(*res->databases) * i);
447     i = 0;
448     for (c = n->child; c; c = c->next)
449     {
450         if (!is_numeric_tag (eh, c) != 102)
451             continue;
452         res->databases[i++] = f_string (eh, c);
453     }
454     return res;
455 }
456
457 static Z_TargetInfo *f_targetInfo(ExpHandle *eh, data1_node *n)
458 {
459     Z_TargetInfo *res = (Z_TargetInfo *)odr_malloc(eh->o, sizeof(*res));
460     data1_node *c;
461
462     res->commonInfo = 0;
463     res->name = 0;
464     res->recentNews = 0;
465     res->icon = 0;
466     res->namedResultSets = 0;
467     res->multipleDBsearch = 0;
468     res->maxResultSets = 0;
469     res->maxResultSize = 0;
470     res->maxTerms = 0;
471     res->timeoutInterval = 0;
472     res->welcomeMessage = 0;
473     res->contactInfo = 0;
474     res->description = 0;
475     res->num_nicknames = 0;
476     res->nicknames = 0;
477     res->usageRest = 0;
478     res->paymentAddr = 0;
479     res->hours = 0;
480     res->num_dbCombinations = 0;
481     res->dbCombinations = 0;
482     res->num_addresses = 0;
483     res->addresses = 0;
484     res->commonAccessInfo = 0;
485     
486     for (c = n->child; c; c = c->next)
487     {
488         int i = 0;
489
490         if (!is_numeric_tag (eh, c))
491             continue;
492         switch (c->u.tag.element->tag->value.numeric)
493         {
494         case 600: res->commonInfo = f_commonInfo(eh, c); break;
495         case 102: res->name = f_string(eh, c); break;
496         case 103: res->recentNews = f_humstring(eh, c); break;
497         case 104: res->icon = NULL; break; /* fix */
498         case 105: res->namedResultSets = f_bool(eh, c); break;
499         case 106: res->multipleDBsearch = f_bool(eh, c); break;
500         case 107: res->maxResultSets = f_integer(eh, c); break;
501         case 108: res->maxResultSize = f_integer(eh, c); break;
502         case 109: res->maxTerms = f_integer(eh, c); break;
503         case 110: res->timeoutInterval = f_intunit(eh, c); break;
504         case 111: res->welcomeMessage = f_humstring(eh, c); break;
505         case 112: res->contactInfo = f_contactInfo(eh, c); break;
506         case 113: res->description = f_humstring(eh, c); break;
507         case 114: 
508             res->num_nicknames = 0;
509             for (n = c->child; n; n = n->next)
510             {
511                 if (is_numeric_tag(eh, n) != 102)
512                     continue;
513                 (res->num_nicknames)++;
514             }
515             if (res->num_nicknames)
516                 res->nicknames =
517                     (char **)odr_malloc (eh->o, res->num_nicknames 
518                                 * sizeof(*res->nicknames));
519             for (n = c->child; n; n = n->next)
520             {
521                 if (is_numeric_tag(eh, n) != 102)
522                     continue;
523                 res->nicknames[i++] = f_string (eh, n);
524             }
525             break;
526         case 115: res->usageRest = f_humstring(eh, c); break;
527         case 116: res->paymentAddr = f_humstring(eh, c); break;
528         case 117: res->hours = f_humstring(eh, c); break;
529         case 118:
530             res->num_dbCombinations = 0;
531             for (n = c->child; n; n = n->next)
532             {
533                 if (!is_numeric_tag(eh, n) != 605)
534                     continue;
535                 (res->num_dbCombinations)++;
536             }
537             if (res->num_dbCombinations)
538                 res->dbCombinations =
539                     (Z_DatabaseList **)odr_malloc (eh->o, res->num_dbCombinations
540                                 * sizeof(*res->dbCombinations));
541             for (n = c->child; n; n = n->next)
542             {
543                 if (!is_numeric_tag(eh, n) != 605)
544                     continue;
545                 res->dbCombinations[i++] = f_databaseList (eh, n);
546             }
547             break;
548         case 119: res->addresses = 0; break; /* fix */
549         case 500: res->commonAccessInfo = f_accessInfo(eh, c); break;
550         }
551     }
552     if (!res->namedResultSets)
553         res->namedResultSets = eh->false_value;
554     if (!res->multipleDBsearch)
555         res->multipleDBsearch = eh->false_value;
556     return res;
557 }
558
559 static Z_DatabaseInfo *f_databaseInfo(ExpHandle *eh, data1_node *n)
560 {
561     Z_DatabaseInfo *res = (Z_DatabaseInfo *)odr_malloc(eh->o, sizeof(*res));
562     data1_node *c;
563
564     res->commonInfo = 0;
565     res->name = 0;
566     res->explainDatabase = 0;
567     res->num_nicknames = 0;
568     res->nicknames = 0;
569     res->icon = 0;
570     res->userFee = 0;
571     res->available = 0;
572     res->titleString = 0;
573     res->num_keywords = 0;
574     res->keywords = 0;
575     res->description = 0;
576     res->associatedDbs = 0;
577     res->subDbs = 0;
578     res->disclaimers = 0;
579     res->news = 0;
580 #ifdef ASN_COMPILED
581     res->u.actualNumber = 0;
582 #else
583     res->recordCount = 0;
584 #endif
585     res->defaultOrder = 0;
586     res->avRecordSize = 0;
587     res->maxRecordSize = 0;
588     res->hours = 0;
589     res->bestTime = 0;
590     res->lastUpdate = 0;
591     res->updateInterval = 0;
592     res->coverage = 0;
593     res->proprietary = 0;
594     res->copyrightText = 0;
595     res->copyrightNotice = 0;
596     res->producerContactInfo = 0;
597     res->supplierContactInfo = 0;
598     res->submissionContactInfo = 0;
599     res->accessInfo = 0;
600     
601     for (c = n->child; c; c = c->next)
602     {
603         int i = 0;
604
605         switch (is_numeric_tag (eh, c))
606         {
607         case 600: res->commonInfo = f_commonInfo(eh, c); break;
608         case 102: res->name = f_string(eh, c); break;
609         case 226: res->explainDatabase = odr_nullval(); break;
610         case 114:
611             res->num_nicknames = 0;
612             for (n = c->child; n; n = n->next)
613             {
614                 if (!is_numeric_tag(eh, n) ||
615                     n->u.tag.element->tag->value.numeric != 102)
616                     continue;
617                 (res->num_nicknames)++;
618             }
619             if (res->num_nicknames)
620                 res->nicknames =
621                     (char **)odr_malloc (eh->o, res->num_nicknames 
622                                 * sizeof(*res->nicknames));
623             for (n = c->child; n; n = n->next)
624             {
625                 if (!is_numeric_tag(eh, n) ||
626                     n->u.tag.element->tag->value.numeric != 102)
627                     continue;
628                 res->nicknames[i++] = f_string (eh, n);
629             }
630             break;
631         case 104: res->icon = 0; break;      /* fix */
632         case 201: res->userFee = f_bool(eh, c); break;
633         case 202: res->available = f_bool(eh, c); break;
634         case 203: res->titleString = f_humstring(eh, c); break;
635         case 227:
636             res->num_keywords = 0;
637             for (n = c->child; n; n = n->next)
638             {
639                 if (!is_numeric_tag(eh, n) != 1000)
640                     continue;
641                 (res->num_keywords)++;
642             }
643             if (res->num_keywords)
644                 res->keywords =
645                     (Z_HumanString **)odr_malloc (eh->o, res->num_keywords 
646                                 * sizeof(*res->keywords));
647             for (n = c->child; n; n = n->next)
648             {
649                 if (!is_numeric_tag(eh, n) != 1000)
650                     continue;
651                 res->keywords[i++] = f_humstring (eh, n);
652             }
653             break;
654         case 113: res->description = f_humstring(eh, c); break;
655         case 205:
656             res->associatedDbs = f_databaseList (eh, c);
657             break;
658         case 206:
659             res->subDbs = f_databaseList (eh, c);
660             break;
661         case 207: res->disclaimers = f_humstring(eh, c); break;
662         case 103: res->news = f_humstring(eh, c); break;
663 #ifdef ASN_COMPILED
664         case 209: res->u.actualNumber =
665                       f_recordCount(eh, c, &res->which); break;
666 #else
667         case 209: res->recordCount =
668                       f_recordCount(eh, c, &res->recordCount_which); break;
669 #endif
670         case 212: res->defaultOrder = f_humstring(eh, c); break;
671         case 213: res->avRecordSize = f_integer(eh, c); break;
672         case 214: res->maxRecordSize = f_integer(eh, c); break;
673         case 215: res->hours = f_humstring(eh, c); break;
674         case 216: res->bestTime = f_humstring(eh, c); break;
675         case 217: res->lastUpdate = f_string(eh, c); break;
676         case 218: res->updateInterval = f_intunit(eh, c); break;
677         case 219: res->coverage = f_humstring(eh, c); break;
678         case 220: res->proprietary = f_bool(eh, c); break;
679         case 221: res->copyrightText = f_humstring(eh, c); break;
680         case 222: res->copyrightNotice = f_humstring(eh, c); break;
681         case 223: res->producerContactInfo = f_contactInfo(eh, c); break;
682         case 224: res->supplierContactInfo = f_contactInfo(eh, c); break;
683         case 225: res->submissionContactInfo = f_contactInfo(eh, c); break;
684         case 500: res->accessInfo = f_accessInfo(eh, c); break;
685         }
686     }
687     if (!res->userFee)
688         res->userFee = eh->false_value;
689     if (!res->available)
690         res->available = eh->true_value;
691     return res;
692 }
693
694 Z_ExplainRecord *data1_nodetoexplain (data1_handle dh, data1_node *n,
695                                       int select, ODR o)
696 {
697     ExpHandle eh;
698     Z_ExplainRecord *res = (Z_ExplainRecord *)odr_malloc(o, sizeof(*res));
699
700     eh.dh = dh;
701     eh.select = select;
702     eh.o = o;
703     eh.false_value = (int *)odr_malloc(eh.o, sizeof(eh.false_value));
704     *eh.false_value = 0;
705     eh.true_value = (int *)odr_malloc(eh.o, sizeof(eh.true_value));
706     *eh.true_value = 1;
707
708     assert(n->which == DATA1N_root);
709     if (strcmp(n->u.root.type, "explain"))
710     {
711         logf(LOG_WARN, "Attempt to convert a non-Explain record");
712         return 0;
713     }
714     for (n = n->child; n; n = n->next)
715     {
716         switch (is_numeric_tag (&eh, n))
717         {
718         case 1:
719             res->which = Z_Explain_targetInfo;
720             if (!(res->u.targetInfo = f_targetInfo(&eh, n)))
721                 return 0;
722             return res;
723         case 2:
724             res->which = Z_Explain_databaseInfo;
725             if (!(res->u.databaseInfo = f_databaseInfo(&eh, n)))
726                 return 0;
727             return res;
728         }
729     }
730     logf(LOG_WARN, "No category in Explain record");
731     return 0;
732 }