Fixed data1_gettagbyname. Bug introduced by previous revision.
[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.15  1998-09-28 12:44:40  adam
8  * Fixed bug in f_integer.
9  *
10  * Revision 1.14  1998/06/08 14:26:41  adam
11  * Fixed bug in f_queryTypeDetails.
12  *
13  * Revision 1.13  1998/06/05 08:58:48  adam
14  * Fixed un-initialised var in f_rpnCapabilities.
15  *
16  * Revision 1.12  1998/05/18 13:07:04  adam
17  * Changed the way attribute sets are handled by the retriaval module.
18  * Extended Explain conversion / schema.
19  * Modified server and client to work with ASN.1 compiled protocol handlers.
20  *
21  * Revision 1.11  1998/04/02 08:27:37  adam
22  * Minor change in definition of Z_TargetInfo. Furhter work on Explain
23  * schema - added AttributeDetails.
24  *
25  * Revision 1.10  1998/03/31 15:13:20  adam
26  * Development towards compiled ASN.1.
27  *
28  * Revision 1.9  1998/03/05 08:07:58  adam
29  * Make data1 to EXPLAIN ignore local tags in root.
30  *
31  * Revision 1.8  1998/02/11 11:53:35  adam
32  * Changed code so that it compiles as C++.
33  *
34  * Revision 1.7  1997/12/09 16:18:16  adam
35  * Work on EXPLAIN schema. First implementation of sub-schema facility
36  * in the *.abs files.
37  *
38  * Revision 1.6  1997/11/24 11:33:56  adam
39  * Using function odr_nullval() instead of global ODR_NULLVAL when
40  * appropriate.
41  *
42  * Revision 1.5  1997/11/19 10:30:06  adam
43  * More explain work.
44  *
45  * Revision 1.4  1997/11/18 09:51:08  adam
46  * Removed element num_children from data1_node. Minor changes in
47  * data1 to Explain.
48  *
49  * Revision 1.3  1997/09/17 12:10:36  adam
50  * YAZ version 1.4.
51  *
52  * Revision 1.2  1995/12/14 16:28:30  quinn
53  * More explain stuff.
54  *
55  * Revision 1.1  1995/12/14  11:09:51  quinn
56  * Work on Explain
57  *
58  *
59  */
60
61 #include <assert.h>
62 #include <string.h>
63 #include <stdlib.h>
64
65 #include <log.h>
66 #include <proto.h>
67 #include <data1.h>
68
69 typedef struct {
70     data1_handle dh;
71     ODR o;
72     int select;
73
74     bool_t *false_value;
75     bool_t *true_value;
76 } ExpHandle;
77
78 static int is_numeric_tag (ExpHandle *eh, data1_node *c)
79 {
80     if (!c || c->which != DATA1N_tag)
81         return 0;
82     if (!c->u.tag.element)
83     {
84         logf(LOG_WARN, "Tag %s is local", c->u.tag.tag);
85         return 0;
86     }
87     if (c->u.tag.element->tag->which != DATA1T_numeric)
88     {
89         logf(LOG_WARN, "Tag %s is not numeric", c->u.tag.tag);
90         return 0;
91     }
92     if (eh->select && !c->u.tag.node_selected)
93         return 0;
94     return c->u.tag.element->tag->value.numeric;
95 }
96
97 static int is_data_tag (ExpHandle *eh, data1_node *c)
98 {
99     if (!c || c->which != DATA1N_data)
100         return 0;
101     if (eh->select && !c->u.tag.node_selected)
102         return 0;
103     return 1;
104 }
105
106 static int *f_integer(ExpHandle *eh, data1_node *c)
107 {
108     int *r;
109     char intbuf[64];
110
111     c = c->child;
112     if (!is_data_tag (eh, c) || c->u.data.len > 63)
113         return 0;
114     r = (int *)odr_malloc(eh->o, sizeof(*r));
115     sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
116     *r = atoi(intbuf);
117     return r;
118 }
119
120 static char *f_string(ExpHandle *eh, data1_node *c)
121 {
122     char *r;
123
124     c = c->child;
125     if (!is_data_tag (eh, c))
126         return 0;
127     r = (char *)odr_malloc(eh->o, c->u.data.len+1);
128     memcpy(r, c->u.data.data, c->u.data.len);
129     r[c->u.data.len] = '\0';
130     return r;
131 }
132
133 static bool_t *f_bool(ExpHandle *eh, data1_node *c)
134 {
135     bool_t *tf;
136     char intbuf[64];
137
138     c = c->child;
139     if (!is_data_tag (eh, c) || c->u.data.len > 63)
140         return 0;
141     tf = (int *)odr_malloc (eh->o, sizeof(*tf));
142     sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
143     *tf = atoi(intbuf);
144     return tf;
145 }
146
147 static Odr_oid *f_oid(ExpHandle *eh, data1_node *c, oid_class oclass)
148 {
149     char oidstr[64];
150     int oid_this[20];
151     oid_value value_for_this;
152
153     c = c->child;
154     if (!is_data_tag (eh, c) || c->u.data.len > 63)
155         return 0;
156     sprintf(oidstr, "%.*s", c->u.data.len, c->u.data.data);
157     value_for_this = oid_getvalbyname(oidstr);
158     if (value_for_this == VAL_NONE)
159     {
160         Odr_oid *oid = odr_getoidbystr(eh->o, oidstr);
161         assert (oid);
162         return oid;
163     }
164     else
165     {
166         struct oident ident;
167
168         ident.oclass = oclass;
169         ident.proto = PROTO_Z3950;
170         ident.value = value_for_this;
171         
172         oid_ent_to_oid (&ident, oid_this);
173     }
174     return odr_oiddup (eh->o, oid_this);
175 }
176
177 static Z_IntUnit *f_intunit(ExpHandle *eh, data1_node *c)
178 {
179     /* fix */
180     return 0;
181 }
182
183 static Z_HumanString *f_humstring(ExpHandle *eh, data1_node *c)
184 {
185     Z_HumanString *r;
186     Z_HumanStringUnit *u;
187
188     c = c->child;
189     if (!is_data_tag (eh, c))
190         return 0;
191     r = (Z_HumanString *)odr_malloc(eh->o, sizeof(*r));
192     r->num_strings = 1;
193     r->strings = (Z_HumanStringUnit **)odr_malloc(eh->o, sizeof(Z_HumanStringUnit*));
194     r->strings[0] = u = (Z_HumanStringUnit *)odr_malloc(eh->o, sizeof(*u));
195     u->language = 0;
196     u->text = (char *)odr_malloc(eh->o, c->u.data.len+1);
197     memcpy(u->text, c->u.data.data, c->u.data.len);
198     u->text[c->u.data.len] = '\0';
199     return r;
200 }
201
202 static Z_CommonInfo *f_commonInfo(ExpHandle *eh, data1_node *n)
203 {
204     Z_CommonInfo *res = (Z_CommonInfo *)odr_malloc(eh->o, sizeof(*res));
205     data1_node *c;
206
207     res->dateAdded = 0;
208     res->dateChanged = 0;
209     res->expiry = 0;
210     res->humanStringLanguage = 0;
211     res->otherInfo = 0;
212
213     for (c = n->child; c; c = c->next)
214     {
215         switch (is_numeric_tag (eh, c))
216         {
217             case 601: res->dateAdded = f_string(eh, c); break;
218             case 602: res->dateChanged = f_string(eh, c); break;
219             case 603: res->expiry = f_string(eh, c); break;
220             case 604: res->humanStringLanguage = f_string(eh, c); break;
221         }
222     }
223     return res;
224 }
225
226 Odr_oid **f_oid_seq (ExpHandle *eh, data1_node *n, int *num, oid_class oclass)
227 {
228     Odr_oid **res;
229     data1_node *c;
230     int i;
231
232     *num = 0;
233     for (c = n->child ; c; c = c->next)
234         if (is_numeric_tag (eh, c) == 1000)
235             ++(*num);
236     if (!*num)
237         return NULL;
238     res = (int **)odr_malloc (eh->o, sizeof(*res) * (*num));
239     for (c = n->child, i = 0 ; c; c = c->next)
240         if (is_numeric_tag (eh, c) == 1000)
241             res[i++] = f_oid (eh, c, oclass);
242     return res;
243 }
244     
245 char **f_string_seq (ExpHandle *eh, data1_node *n, int *num)
246 {
247     char **res;
248     data1_node *c;
249     int i;
250
251     *num = 0;
252     for (c = n->child ; c; c = c->next)
253     {
254         if (is_numeric_tag (eh, c) != 1001)
255             continue;
256         ++(*num);
257     }
258     if (!*num)
259         return NULL;
260     res = (char **)odr_malloc (eh->o, sizeof(*res) * (*num));
261     for (c = n->child, i = 0 ; c; c = c->next)
262     {
263         if (is_numeric_tag (eh, c) != 1001)
264             continue;
265         res[i++] = f_string (eh, c);
266     }
267     return res;
268 }
269
270 Z_ProximitySupport *f_proximitySupport (ExpHandle *eh, data1_node *n)
271 {
272     Z_ProximitySupport *res = (Z_ProximitySupport *)
273         odr_malloc (eh->o, sizeof(*res));
274     res->anySupport = eh->false_value;
275     res->num_unitsSupported = 0;
276     res->unitsSupported = 0;
277     return res;
278 }
279
280 Z_RpnCapabilities *f_rpnCapabilities (ExpHandle *eh, data1_node *n)
281 {
282     Z_RpnCapabilities *res = (Z_RpnCapabilities *)
283         odr_malloc (eh->o, sizeof(*res));
284     data1_node *c;
285
286     res->num_operators = 0;
287     res->operators = NULL;
288     res->resultSetAsOperandSupported = eh->false_value;
289     res->restrictionOperandSupported = eh->false_value;
290     res->proximity = NULL;
291
292     for (c = n->child; c; c = c->next)
293     {
294         int i = 0;
295         switch (is_numeric_tag(eh, c))
296         {
297         case 550:
298             for (n = c->child; n; n = n->next)
299             {
300                 if (is_numeric_tag(eh, n) != 551)
301                     continue;
302                 (res->num_operators)++;
303             }
304             if (res->num_operators)
305                 res->operators = (int **)
306                     odr_malloc (eh->o, res->num_operators
307                                 * sizeof(*res->operators));
308             for (n = c->child; n; n = n->next)
309             {
310                 if (is_numeric_tag(eh, n) != 551)
311                     continue;
312                 res->operators[i++] = f_integer (eh, n);
313             }
314             break;
315         case 552:
316             res->resultSetAsOperandSupported = f_bool (eh, c);
317             break;
318         case 553:
319             res->restrictionOperandSupported = f_bool (eh, c);
320             break;
321         case 554:
322             res->proximity = f_proximitySupport (eh, c);
323             break;
324         }
325     }
326     return res;
327 }
328
329 Z_QueryTypeDetails *f_queryTypeDetails (ExpHandle *eh, data1_node *n)
330 {
331     Z_QueryTypeDetails *res = (Z_QueryTypeDetails *)
332         odr_malloc(eh->o, sizeof(*res));
333     data1_node *c;
334
335     res->which = Z_QueryTypeDetails_rpn;
336     res->u.rpn = 0;
337     for (c = n->child; c; c = c->next)
338     {
339         switch (is_numeric_tag(eh, c))
340         {
341         case 519:
342             res->which = Z_QueryTypeDetails_rpn;
343             res->u.rpn = f_rpnCapabilities (eh, c);
344             break;
345         case 520:
346             break;
347         case 521:
348             break;
349         }
350     }
351     return res;
352 }
353
354 static Z_AccessInfo *f_accessInfo(ExpHandle *eh, data1_node *n)
355 {
356     Z_AccessInfo *res = (Z_AccessInfo *)odr_malloc(eh->o, sizeof(*res));
357     data1_node *c;
358
359     res->num_queryTypesSupported = 0;
360     res->queryTypesSupported = 0;
361     res->num_diagnosticsSets = 0;
362     res->diagnosticsSets = 0;
363     res->num_attributeSetIds = 0;
364     res->attributeSetIds = 0;
365     res->num_schemas = 0;
366     res->schemas = 0;
367     res->num_recordSyntaxes = 0;
368     res->recordSyntaxes = 0;
369     res->num_resourceChallenges = 0;
370     res->resourceChallenges = 0;
371     res->restrictedAccess = 0;
372     res->costInfo = 0;
373     res->num_variantSets = 0;
374     res->variantSets = 0;
375     res->num_elementSetNames = 0;
376     res->elementSetNames = 0;
377     res->num_unitSystems = 0;
378     res->unitSystems = 0;
379
380     for (c = n->child; c; c = c->next)
381     {
382         int i = 0;
383         switch (is_numeric_tag (eh, c))
384         {
385         case 501:
386             for (n = c->child; n; n = n->next)
387             {
388                 if (is_numeric_tag(eh, n) != 518)
389                     continue;
390                 (res->num_queryTypesSupported)++;
391             }
392             if (res->num_queryTypesSupported)
393                 res->queryTypesSupported =
394                     (Z_QueryTypeDetails **)
395                     odr_malloc (eh->o, res->num_queryTypesSupported
396                                 * sizeof(*res->queryTypesSupported));
397             for (n = c->child; n; n = n->next)
398             {
399                 if (is_numeric_tag(eh, n) != 518)
400                     continue;
401                 res->queryTypesSupported[i++] = f_queryTypeDetails (eh, n);
402             }
403             break;
404         case 503:
405             res->diagnosticsSets =
406                 f_oid_seq(eh, c, &res->num_diagnosticsSets, CLASS_DIAGSET);
407             break;
408         case 505:
409             res->attributeSetIds =
410                 f_oid_seq(eh, c, &res->num_attributeSetIds, CLASS_ATTSET);
411             break;
412         case 507:
413             res->schemas =
414                 f_oid_seq(eh, c, &res->num_schemas, CLASS_SCHEMA);
415             break;
416         case 509:
417             res->recordSyntaxes =
418                 f_oid_seq (eh, c, &res->num_recordSyntaxes, CLASS_RECSYN);
419             break;
420         case 511:
421             res->resourceChallenges =
422                 f_oid_seq (eh, c, &res->num_resourceChallenges, CLASS_RESFORM);
423             break;
424         case 513: res->restrictedAccess = NULL; break; /* fix */
425         case 514: res->costInfo = NULL; break; /* fix */
426         case 515:
427             res->variantSets =
428                 f_oid_seq (eh, c, &res->num_variantSets, CLASS_VARSET);
429             break;
430         case 516:
431             res->elementSetNames =
432                 f_string_seq (eh, c, &res->num_elementSetNames);
433             break;
434         case 517:
435             res->unitSystems = f_string_seq (eh, c, &res->num_unitSystems);
436             break;
437         }
438     }
439     return res;
440 }
441
442 static int *f_recordCount(ExpHandle *eh, data1_node *c, int *which)
443 {
444     int *r= (int *)odr_malloc(eh->o, sizeof(*r));
445     int *wp = which;
446     char intbuf[64];
447
448     c = c->child;
449     if (!is_numeric_tag (eh, c))
450         return 0;
451     if (c->u.tag.element->tag->value.numeric == 210)
452         *wp = Z_DatabaseInfo_actualNumber;
453     else if (c->u.tag.element->tag->value.numeric == 211)
454         *wp = Z_DatabaseInfo_approxNumber;
455     else
456         return 0;
457     if (!c->child || c->child->which != DATA1N_data)
458         return 0;
459     sprintf(intbuf, "%.*s", c->child->u.data.len, c->child->u.data.data);
460     *r = atoi(intbuf);
461     return r;
462 }
463
464 static Z_ContactInfo *f_contactInfo(ExpHandle *eh, data1_node *n)
465 {
466     Z_ContactInfo *res = (Z_ContactInfo *)
467         odr_malloc (eh->o, sizeof(*res));
468     data1_node *c;
469     
470     res->name = 0;
471     res->description = 0;
472     res->address = 0;
473     res->email = 0;
474     res->phone = 0;
475     
476     for (c = n->child; c; c = c->next)
477     {
478         switch (is_numeric_tag (eh, c))
479         {
480         case 102: res->name = f_string (eh, c); break;
481         case 113: res->description = f_humstring (eh, c); break;
482         case 127: res->address = f_humstring (eh, c); break;
483         case 128: res->email = f_string (eh, c); break;
484         case 129: res->phone = f_string (eh, c); break;
485         }
486     }
487     return res;
488 }
489
490 static Z_DatabaseList *f_databaseList(ExpHandle *eh, data1_node *n)
491 {
492     data1_node *c;
493     Z_DatabaseList *res;
494     int i = 0;
495     
496     for (c = n->child; c; c = c->next)
497     {
498         if (!is_numeric_tag (eh, c) != 102) 
499             continue;
500         ++i;
501     }
502     if (!i)
503         return NULL;
504
505     res = (Z_DatabaseList *)odr_malloc (eh->o, sizeof(*res));
506     
507     res->num_databases = i;
508     res->databases = (char **)odr_malloc (eh->o, sizeof(*res->databases) * i);
509     i = 0;
510     for (c = n->child; c; c = c->next)
511     {
512         if (!is_numeric_tag (eh, c) != 102)
513             continue;
514         res->databases[i++] = f_string (eh, c);
515     }
516     return res;
517 }
518
519 static Z_NetworkAddressIA *f_networkAddressIA(ExpHandle *eh, data1_node *n)
520 {
521     Z_NetworkAddressIA *res = (Z_NetworkAddressIA *)
522         odr_malloc (eh->o, sizeof(*res));
523     data1_node *c;
524     
525     res->hostAddress = 0;
526     res->port = 0;
527
528     for (c = n->child; c; c = c->next)
529     {
530         switch (is_numeric_tag (eh, c))
531         {
532         case 121: res->hostAddress = f_string (eh, c); break;
533         case 122: res->port = f_integer (eh, c); break;
534         }
535     }
536     return res;
537 }
538
539 static Z_NetworkAddressOther *f_networkAddressOther(ExpHandle *eh,
540                                                     data1_node *n)
541 {
542     Z_NetworkAddressOther *res = (Z_NetworkAddressOther *)
543         odr_malloc (eh->o, sizeof(*res));
544     data1_node *c;
545
546     res->type = 0;
547     res->address = 0;
548
549     for (c = n->child; c; c = c->next)
550     {
551         switch (is_numeric_tag (eh, c))
552         {
553         case 124: res->type = f_string (eh, c); break;
554         case 121: res->address = f_string (eh, c); break;
555         }
556     }
557     return res;
558 }
559
560 static Z_NetworkAddress **f_networkAddresses(ExpHandle *eh, data1_node *n, 
561                                              int *num)
562 {
563     Z_NetworkAddress **res = NULL;
564     data1_node *c;
565     int i = 0;
566     
567     *num = 0;
568     for (c = n->child; c; c = c->next)
569     {
570         switch (is_numeric_tag (eh, c))
571         {
572         case 120:
573         case 123:
574             (*num)++;
575             break;
576         }
577     }
578
579     if (*num)
580         res = (Z_NetworkAddress **) odr_malloc (eh->o, sizeof(*res) * (*num));
581                                                
582     for (c = n->child; c; c = c->next)
583     {
584         switch (is_numeric_tag (eh, c))
585         {
586         case 120:
587             res[i] = (Z_NetworkAddress *) odr_malloc (eh->o, sizeof(**res));
588             res[i]->which = Z_NetworkAddress_iA;
589             res[i]->u.internetAddress = f_networkAddressIA(eh, c);
590             i++;
591             break;
592         case 123:
593             res[i] = (Z_NetworkAddress *) odr_malloc (eh->o, sizeof(**res));
594             res[i]->which = Z_NetworkAddress_other;
595             res[i]->u.other = f_networkAddressOther(eh, c);
596             i++;
597             break;
598         }
599     }
600     return res;
601 }
602
603 static Z_CategoryInfo *f_categoryInfo(ExpHandle *eh, data1_node *n)
604 {
605     Z_CategoryInfo *res = (Z_CategoryInfo *)odr_malloc(eh->o, sizeof(*res));
606     data1_node *c;
607
608     res->category = 0;
609     res->originalCategory = 0;
610     res->description = 0;
611     res->asn1Module = 0;
612     for (c = n->child; c; c = c->next)
613     {
614         switch (is_numeric_tag (eh, c))
615         {
616         case 102: res->category = f_string(eh, c); break;
617         case 302: res->originalCategory = f_string(eh, c); break;
618         case 113: res->description = f_humstring(eh, c); break;
619         case 303: res->asn1Module = f_string (eh, c); break;
620         }
621     }
622     return res;
623 }
624
625 static Z_CategoryList *f_categoryList(ExpHandle *eh, data1_node *n)
626 {
627     Z_CategoryList *res = (Z_CategoryList *)odr_malloc(eh->o, sizeof(*res));
628     data1_node *c;
629
630     res->commonInfo = 0;
631     res->num_categories = 0;
632     res->categories = NULL;
633
634     for (c = n->child; c; c = c->next)
635     {
636         int i = 0;
637
638         switch (is_numeric_tag (eh, c))
639         {
640         case 600: res->commonInfo = f_commonInfo(eh, c); break;
641         case 300:
642             for (n = c->child; n; n = n->next)
643             {
644                 if (is_numeric_tag(eh, n) != 301)
645                     continue;
646                 (res->num_categories)++;
647             }
648             if (res->num_categories)
649                 res->categories =
650                     (Z_CategoryInfo **)odr_malloc (eh->o, res->num_categories 
651                                                    * sizeof(*res->categories));
652             for (n = c->child; n; n = n->next)
653             {
654                 if (is_numeric_tag(eh, n) != 301)
655                     continue;
656                 res->categories[i++] = f_categoryInfo (eh, n);
657             }
658             break;
659         }
660     }
661     assert (res->num_categories && res->categories);
662     return res;
663 }
664
665 static Z_TargetInfo *f_targetInfo(ExpHandle *eh, data1_node *n)
666 {
667     Z_TargetInfo *res = (Z_TargetInfo *)odr_malloc(eh->o, sizeof(*res));
668     data1_node *c;
669
670     res->commonInfo = 0;
671     res->name = 0;
672     res->recentNews = 0;
673     res->icon = 0;
674     res->namedResultSets = 0;
675     res->multipleDBsearch = 0;
676     res->maxResultSets = 0;
677     res->maxResultSize = 0;
678     res->maxTerms = 0;
679     res->timeoutInterval = 0;
680     res->welcomeMessage = 0;
681     res->contactInfo = 0;
682     res->description = 0;
683     res->num_nicknames = 0;
684     res->nicknames = 0;
685     res->usageRest = 0;
686     res->paymentAddr = 0;
687     res->hours = 0;
688     res->num_dbCombinations = 0;
689     res->dbCombinations = 0;
690     res->num_addresses = 0;
691     res->addresses = 0;
692     res->num_languages = 0;
693     res->languages = NULL;
694     res->commonAccessInfo = 0;
695     
696     for (c = n->child; c; c = c->next)
697     {
698         int i = 0;
699
700         switch (is_numeric_tag (eh, c))
701         {
702         case 600: res->commonInfo = f_commonInfo(eh, c); break;
703         case 102: res->name = f_string(eh, c); break;
704         case 103: res->recentNews = f_humstring(eh, c); break;
705         case 104: res->icon = NULL; break; /* fix */
706         case 105: res->namedResultSets = f_bool(eh, c); break;
707         case 106: res->multipleDBsearch = f_bool(eh, c); break;
708         case 107: res->maxResultSets = f_integer(eh, c); break;
709         case 108: res->maxResultSize = f_integer(eh, c); break;
710         case 109: res->maxTerms = f_integer(eh, c); break;
711         case 110: res->timeoutInterval = f_intunit(eh, c); break;
712         case 111: res->welcomeMessage = f_humstring(eh, c); break;
713         case 112: res->contactInfo = f_contactInfo(eh, c); break;
714         case 113: res->description = f_humstring(eh, c); break;
715         case 114: 
716             res->num_nicknames = 0;
717             for (n = c->child; n; n = n->next)
718             {
719                 if (is_numeric_tag(eh, n) != 102)
720                     continue;
721                 (res->num_nicknames)++;
722             }
723             if (res->num_nicknames)
724                 res->nicknames =
725                     (char **)odr_malloc (eh->o, res->num_nicknames 
726                                 * sizeof(*res->nicknames));
727             for (n = c->child; n; n = n->next)
728             {
729                 if (is_numeric_tag(eh, n) != 102)
730                     continue;
731                 res->nicknames[i++] = f_string (eh, n);
732             }
733             break;
734         case 115: res->usageRest = f_humstring(eh, c); break;
735         case 116: res->paymentAddr = f_humstring(eh, c); break;
736         case 117: res->hours = f_humstring(eh, c); break;
737         case 118:
738             res->num_dbCombinations = 0;
739             for (n = c->child; n; n = n->next)
740             {
741                 if (!is_numeric_tag(eh, n) != 605)
742                     continue;
743                 (res->num_dbCombinations)++;
744             }
745             if (res->num_dbCombinations)
746                 res->dbCombinations =
747                     (Z_DatabaseList **)odr_malloc (eh->o, res->num_dbCombinations
748                                 * sizeof(*res->dbCombinations));
749             for (n = c->child; n; n = n->next)
750             {
751                 if (!is_numeric_tag(eh, n) != 605)
752                     continue;
753                 res->dbCombinations[i++] = f_databaseList (eh, n);
754             }
755             break;
756         case 119: 
757             res->addresses =
758                 f_networkAddresses (eh, c, &res->num_addresses);
759             break;
760         case 125:
761             res->num_languages = 0;
762             for (n = c->child; n; n = n->next)
763             {
764                 if (!is_numeric_tag(eh, n) != 126)
765                     continue;
766                 (res->num_languages)++;
767             }
768             if (res->num_languages)
769                 res->languages = (char **)
770                     odr_malloc (eh->o, res->num_languages *
771                                 sizeof(*res->languages));
772             for (n = c->child; n; n = n->next)
773             {
774                 if (!is_numeric_tag(eh, n) != 126)
775                     continue;
776                 res->languages[i++] = f_string (eh, n);
777             }
778             break;
779         case 500: res->commonAccessInfo = f_accessInfo(eh, c); break;
780         }
781     }
782     if (!res->namedResultSets)
783         res->namedResultSets = eh->false_value;
784     if (!res->multipleDBsearch)
785         res->multipleDBsearch = eh->false_value;
786     return res;
787 }
788
789 static Z_DatabaseInfo *f_databaseInfo(ExpHandle *eh, data1_node *n)
790 {
791     Z_DatabaseInfo *res = (Z_DatabaseInfo *)odr_malloc(eh->o, sizeof(*res));
792     data1_node *c;
793
794     res->commonInfo = 0;
795     res->name = 0;
796     res->explainDatabase = 0;
797     res->num_nicknames = 0;
798     res->nicknames = 0;
799     res->icon = 0;
800     res->userFee = 0;
801     res->available = 0;
802     res->titleString = 0;
803     res->num_keywords = 0;
804     res->keywords = 0;
805     res->description = 0;
806     res->associatedDbs = 0;
807     res->subDbs = 0;
808     res->disclaimers = 0;
809     res->news = 0;
810     res->u.actualNumber = 0;
811     res->defaultOrder = 0;
812     res->avRecordSize = 0;
813     res->maxRecordSize = 0;
814     res->hours = 0;
815     res->bestTime = 0;
816     res->lastUpdate = 0;
817     res->updateInterval = 0;
818     res->coverage = 0;
819     res->proprietary = 0;
820     res->copyrightText = 0;
821     res->copyrightNotice = 0;
822     res->producerContactInfo = 0;
823     res->supplierContactInfo = 0;
824     res->submissionContactInfo = 0;
825     res->accessInfo = 0;
826     
827     for (c = n->child; c; c = c->next)
828     {
829         int i = 0;
830
831         switch (is_numeric_tag (eh, c))
832         {
833         case 600: res->commonInfo = f_commonInfo(eh, c); break;
834         case 102: res->name = f_string(eh, c); break;
835         case 226: res->explainDatabase = odr_nullval(); break;
836         case 114:
837             res->num_nicknames = 0;
838             for (n = c->child; n; n = n->next)
839             {
840                 if (!is_numeric_tag(eh, n) ||
841                     n->u.tag.element->tag->value.numeric != 102)
842                     continue;
843                 (res->num_nicknames)++;
844             }
845             if (res->num_nicknames)
846                 res->nicknames =
847                     (char **)odr_malloc (eh->o, res->num_nicknames 
848                                 * sizeof(*res->nicknames));
849             for (n = c->child; n; n = n->next)
850             {
851                 if (!is_numeric_tag(eh, n) ||
852                     n->u.tag.element->tag->value.numeric != 102)
853                     continue;
854                 res->nicknames[i++] = f_string (eh, n);
855             }
856             break;
857         case 104: res->icon = 0; break;      /* fix */
858         case 201: res->userFee = f_bool(eh, c); break;
859         case 202: res->available = f_bool(eh, c); break;
860         case 203: res->titleString = f_humstring(eh, c); break;
861         case 227:
862             res->num_keywords = 0;
863             for (n = c->child; n; n = n->next)
864             {
865                 if (!is_numeric_tag(eh, n) != 1000)
866                     continue;
867                 (res->num_keywords)++;
868             }
869             if (res->num_keywords)
870                 res->keywords =
871                     (Z_HumanString **)odr_malloc (eh->o, res->num_keywords 
872                                 * sizeof(*res->keywords));
873             for (n = c->child; n; n = n->next)
874             {
875                 if (!is_numeric_tag(eh, n) != 1000)
876                     continue;
877                 res->keywords[i++] = f_humstring (eh, n);
878             }
879             break;
880         case 113: res->description = f_humstring(eh, c); break;
881         case 205:
882             res->associatedDbs = f_databaseList (eh, c);
883             break;
884         case 206:
885             res->subDbs = f_databaseList (eh, c);
886             break;
887         case 207: res->disclaimers = f_humstring(eh, c); break;
888         case 103: res->news = f_humstring(eh, c); break;
889         case 209: res->u.actualNumber =
890                       f_recordCount(eh, c, &res->which); break;
891         case 212: res->defaultOrder = f_humstring(eh, c); break;
892         case 213: res->avRecordSize = f_integer(eh, c); break;
893         case 214: res->maxRecordSize = f_integer(eh, c); break;
894         case 215: res->hours = f_humstring(eh, c); break;
895         case 216: res->bestTime = f_humstring(eh, c); break;
896         case 217: res->lastUpdate = f_string(eh, c); break;
897         case 218: res->updateInterval = f_intunit(eh, c); break;
898         case 219: res->coverage = f_humstring(eh, c); break;
899         case 220: res->proprietary = f_bool(eh, c); break;
900         case 221: res->copyrightText = f_humstring(eh, c); break;
901         case 222: res->copyrightNotice = f_humstring(eh, c); break;
902         case 223: res->producerContactInfo = f_contactInfo(eh, c); break;
903         case 224: res->supplierContactInfo = f_contactInfo(eh, c); break;
904         case 225: res->submissionContactInfo = f_contactInfo(eh, c); break;
905         case 500: res->accessInfo = f_accessInfo(eh, c); break;
906         }
907     }
908     if (!res->userFee)
909         res->userFee = eh->false_value;
910     if (!res->available)
911         res->available = eh->true_value;
912     return res;
913 }
914
915 Z_StringOrNumeric *f_stringOrNumeric (ExpHandle *eh, data1_node *n)
916 {
917     Z_StringOrNumeric *res = (Z_StringOrNumeric *)
918         odr_malloc (eh->o, sizeof(*res));
919     data1_node *c;
920     for (c = n->child; c; c = c->next)
921     {
922         switch (is_numeric_tag (eh, c))
923         {
924         case 1001:
925             res->which = Z_StringOrNumeric_string;
926             res->u.string = f_string (eh, c);
927             break;
928         case 1002:
929             res->which = Z_StringOrNumeric_numeric;
930             res->u.numeric = f_integer (eh, c);
931             break;
932         }
933     }
934     return res;
935 }
936
937 Z_AttributeDescription *f_attributeDescription (
938     ExpHandle *eh, data1_node *n)
939 {
940     Z_AttributeDescription *res = (Z_AttributeDescription *)
941         odr_malloc(eh->o, sizeof(*res));
942     data1_node *c;
943     int i = 0;
944         
945     res->name = 0;
946     res->description = 0;
947     res->attributeValue = 0;
948     res->num_equivalentAttributes = 0;
949     res->equivalentAttributes = 0;
950
951     for (c = n->child; c; c = c->next)
952     {
953         switch (is_numeric_tag (eh, c))
954         {
955         case 102: res->name = f_string (eh, c); break;
956         case 113: res->description = f_humstring (eh, c); break;
957         case 710: res->attributeValue = f_stringOrNumeric (eh, c); break;
958         case 752: (res->num_equivalentAttributes++); break;
959         }
960     }
961     if (res->num_equivalentAttributes)
962         res->equivalentAttributes = (Z_StringOrNumeric **)
963             odr_malloc (eh->o, sizeof(*res->equivalentAttributes) *
964                         res->num_equivalentAttributes);
965     for (c = n->child; c; c = c->next)
966         if (is_numeric_tag (eh, c) == 752)
967             res->equivalentAttributes[i++] = f_stringOrNumeric (eh, c);
968     return res;
969 }
970
971 Z_AttributeType *f_attributeType (ExpHandle *eh, data1_node *n)
972 {
973     Z_AttributeType *res = (Z_AttributeType *)
974         odr_malloc(eh->o, sizeof(*res));
975     data1_node *c;
976
977     res->name = 0;
978     res->description = 0;
979     res->attributeType = 0;
980     res->num_attributeValues = 0;
981     res->attributeValues = 0;
982
983     for (c = n->child; c; c = c->next)
984     {
985         int i = 0;
986         switch (is_numeric_tag (eh, c))
987         {
988         case 102: res->name = f_string (eh, c); break;
989         case 113: res->description = f_humstring (eh, c); break;
990         case 704: res->attributeType = f_integer (eh, c); break;
991         case 708:
992             for (n = c->child; n; n = n->next)
993             {
994                 if (is_numeric_tag(eh, n) != 709)
995                     continue;
996                 (res->num_attributeValues)++;
997             }
998             if (res->num_attributeValues)
999                 res->attributeValues = (Z_AttributeDescription **)
1000                     odr_malloc (eh->o, res->num_attributeValues
1001                                 * sizeof(*res->attributeValues));
1002             for (n = c->child; n; n = n->next)
1003             {
1004                 if (is_numeric_tag(eh, n) != 709)
1005                     continue;
1006                 res->attributeValues[i++] = f_attributeDescription (eh, n);
1007             }
1008             break;
1009         }
1010     }
1011     return res;
1012 }
1013
1014 Z_AttributeSetInfo *f_attributeSetInfo (ExpHandle *eh, data1_node *n)
1015 {
1016     Z_AttributeSetInfo *res = (Z_AttributeSetInfo *)
1017         odr_malloc(eh->o, sizeof(*res));
1018     data1_node *c;
1019
1020     res->commonInfo = 0;
1021     res->attributeSet = 0;
1022     res->name = 0;
1023     res->num_attributes = 0;
1024     res->attributes = 0;
1025     res->description = 0;
1026     for (c = n->child; c; c = c->next)
1027     {
1028         int i = 0;
1029         switch (is_numeric_tag (eh, c))
1030         {
1031         case 600: res->commonInfo = f_commonInfo (eh, c); break;
1032         case 1000: res->attributeSet = f_oid (eh, c, CLASS_ATTSET); break;
1033         case 102: res->name = f_string (eh, c); break;
1034         case 750:
1035             for (n = c->child; n; n = n->next)
1036             {
1037                 if (is_numeric_tag(eh, n) != 751)
1038                     continue;
1039                 (res->num_attributes)++;
1040             }
1041             if (res->num_attributes)
1042                 res->attributes = (Z_AttributeType **)
1043                     odr_malloc (eh->o, res->num_attributes
1044                                 * sizeof(*res->attributes));
1045             for (n = c->child; n; n = n->next)
1046             {
1047                 if (is_numeric_tag(eh, n) != 751)
1048                     continue;
1049                 res->attributes[i++] = f_attributeType (eh, n);
1050             }
1051             break;
1052         case 113: res->description = f_humstring (eh, c); break;
1053         }
1054     }
1055     return res;
1056 }
1057
1058 Z_OmittedAttributeInterpretation *f_omittedAttributeInterpretation (
1059     ExpHandle *eh, data1_node *n)
1060 {
1061     Z_OmittedAttributeInterpretation *res = (Z_OmittedAttributeInterpretation*)
1062         odr_malloc (eh->o, sizeof(*res));
1063     data1_node *c;
1064
1065     res->defaultValue = 0;
1066     res->defaultDescription = 0;
1067     for (c = n->child; c; c = c->next)
1068     {
1069         switch (is_numeric_tag (eh, c))
1070         {
1071         case 706:
1072             res->defaultValue = f_stringOrNumeric (eh, c);
1073             break;
1074         case 113:
1075             res->defaultDescription = f_humstring(eh, c);
1076             break;
1077         }
1078     }
1079     return res;
1080 }
1081
1082 Z_AttributeValue *f_attributeValue (ExpHandle *eh, data1_node *n)
1083 {
1084     Z_AttributeValue *res = (Z_AttributeValue *)
1085         odr_malloc (eh->o, sizeof(*res));
1086     data1_node *c;
1087
1088     res->value = 0;
1089     res->description = 0;
1090     res->num_subAttributes = 0;
1091     res->subAttributes = 0;
1092     res->num_superAttributes = 0;
1093     res->superAttributes = 0;
1094     res->partialSupport = 0;
1095     for (c = n->child; c; c = c->next)
1096     {
1097         int i = 0;
1098         switch (is_numeric_tag (eh, c))
1099         {
1100         case 710:
1101             res->value = f_stringOrNumeric (eh, c);  break;
1102         case 113:
1103             res->description = f_humstring (eh, c); break;
1104         case 712:
1105             for (n = c->child; n; n = n->next)
1106             {
1107                 if (is_numeric_tag(eh, n) != 713)
1108                     continue;
1109                 (res->num_subAttributes)++;
1110             }
1111             if (res->num_subAttributes)
1112                 res->subAttributes =
1113                     (Z_StringOrNumeric **)
1114                     odr_malloc (eh->o, res->num_subAttributes
1115                                 * sizeof(*res->subAttributes));
1116             for (n = c->child; n; n = n->next)
1117             {
1118                 if (is_numeric_tag(eh, n) != 713)
1119                     continue;
1120                 res->subAttributes[i++] = f_stringOrNumeric (eh, n);
1121             }
1122             break;
1123         case 714:
1124             for (n = c->child; n; n = n->next)
1125             {
1126                 if (is_numeric_tag(eh, n) != 715)
1127                     continue;
1128                 (res->num_superAttributes)++;
1129             }
1130             if (res->num_superAttributes)
1131                 res->superAttributes =
1132                     (Z_StringOrNumeric **)
1133                     odr_malloc (eh->o, res->num_superAttributes
1134                                 * sizeof(*res->superAttributes));
1135             for (n = c->child; n; n = n->next)
1136             {
1137                 if (is_numeric_tag(eh, n) != 715)
1138                     continue;
1139                 res->superAttributes[i++] = f_stringOrNumeric (eh, n);
1140             }
1141             break;
1142         case 711:
1143             res->partialSupport = odr_nullval ();
1144             break;
1145         }
1146     }
1147     return res;
1148 }
1149
1150 Z_AttributeTypeDetails *f_attributeTypeDetails (ExpHandle *eh, data1_node *n)
1151 {
1152     Z_AttributeTypeDetails *res = (Z_AttributeTypeDetails *)
1153         odr_malloc(eh->o, sizeof(*res));
1154     data1_node *c;
1155     res->attributeType = 0;
1156     res->defaultIfOmitted = 0;
1157     res->num_attributeValues = 0;
1158     res->attributeValues = 0;
1159     for (c = n->child; c; c = c->next)
1160     {
1161         int i = 0;
1162         switch (is_numeric_tag (eh, c))
1163         {
1164         case 704: res->attributeType = f_integer (eh, c); break;
1165         case 705:
1166             res->defaultIfOmitted = f_omittedAttributeInterpretation (eh, c);
1167             break;
1168         case 708:
1169             for (n = c->child; n; n = n->next)
1170             {
1171                 if (is_numeric_tag(eh, n) != 709)
1172                     continue;
1173                 (res->num_attributeValues)++;
1174             }
1175             if (res->num_attributeValues)
1176                 res->attributeValues =
1177                     (Z_AttributeValue **)
1178                     odr_malloc (eh->o, res->num_attributeValues
1179                                 * sizeof(*res->attributeValues));
1180             for (n = c->child; n; n = n->next)
1181             {
1182                 if (is_numeric_tag(eh, n) != 709)
1183                     continue;
1184                 res->attributeValues[i++] = f_attributeValue (eh, n);
1185             }
1186             break;
1187         }
1188     }
1189     return res;
1190 }
1191
1192 Z_AttributeSetDetails *f_attributeSetDetails (ExpHandle *eh, data1_node *n)
1193 {
1194     Z_AttributeSetDetails *res = (Z_AttributeSetDetails *)
1195         odr_malloc(eh->o, sizeof(*res));
1196     data1_node *c;
1197     
1198     res->attributeSet = 0;
1199     res->num_attributesByType = 0;
1200     res->attributesByType = 0;
1201     for (c = n->child; c; c = c->next)
1202     {
1203         int i = 0;
1204         switch (is_numeric_tag (eh, c))
1205         {
1206         case 1000: res->attributeSet = f_oid(eh, c, CLASS_ATTSET); break;
1207         case 702:
1208             for (n = c->child; n; n = n->next)
1209             {
1210                 if (is_numeric_tag(eh, n) != 703)
1211                     continue;
1212                 (res->num_attributesByType)++;
1213             }
1214             if (res->num_attributesByType)
1215                 res->attributesByType =
1216                     (Z_AttributeTypeDetails **)
1217                     odr_malloc (eh->o, res->num_attributesByType
1218                                 * sizeof(*res->attributesByType));
1219             for (n = c->child; n; n = n->next)
1220             {
1221                 if (is_numeric_tag(eh, n) != 703)
1222                     continue;
1223                 res->attributesByType[i++] = f_attributeTypeDetails (eh, n);
1224             }
1225             break;
1226         }
1227     }
1228     return res;
1229 }
1230
1231 Z_AttributeValueList *f_attributeValueList (ExpHandle *eh, data1_node *n)
1232 {
1233     Z_AttributeValueList *res = (Z_AttributeValueList *)
1234         odr_malloc (eh->o, sizeof(*res));
1235     data1_node *c;
1236     int i = 0;
1237
1238     res->num_attributes = 0;
1239     res->attributes = 0;
1240     for (c = n->child; c; c = c->next)
1241         if (is_numeric_tag (eh, c) == 710)
1242             (res->num_attributes)++;
1243     if (res->num_attributes)
1244     {
1245         res->attributes = (Z_StringOrNumeric **)
1246             odr_malloc (eh->o, res->num_attributes * sizeof(*res->attributes));
1247     }
1248     for (c = n->child; c; c = c->next)
1249         if (is_numeric_tag(eh, c) == 710)
1250             res->attributes[i++] = f_stringOrNumeric (eh, c);
1251     return res;
1252 }
1253
1254 Z_AttributeOccurrence *f_attributeOccurrence (ExpHandle *eh, data1_node *n)
1255 {
1256     Z_AttributeOccurrence *res = (Z_AttributeOccurrence *)
1257         odr_malloc (eh->o, sizeof(*res));
1258     data1_node *c;
1259
1260     res->attributeSet = 0;
1261     res->attributeType = 0;
1262     res->mustBeSupplied = 0;
1263     res->which = Z_AttributeOcc_any_or_none;
1264     res->attributeValues.any_or_none = odr_nullval ();
1265
1266     for (c = n->child; c; c = c->next)
1267     {
1268         switch (is_numeric_tag (eh, c))
1269         {
1270         case 1000:
1271             res->attributeSet = f_oid (eh, c, CLASS_ATTSET); break;
1272         case 704:
1273             res->attributeType = f_integer (eh, c); break;
1274         case 720:
1275             res->mustBeSupplied = odr_nullval (); break;
1276         case 721:
1277             res->which = Z_AttributeOcc_any_or_none;
1278             res->attributeValues.any_or_none = odr_nullval ();
1279             break;
1280         case 722:
1281             res->which = Z_AttributeOcc_specific;
1282             res->attributeValues.specific = f_attributeValueList (eh, c);
1283             break;
1284         }
1285     }
1286     return res;
1287 }
1288
1289 Z_AttributeCombination *f_attributeCombination (ExpHandle *eh, data1_node *n)
1290 {
1291     Z_AttributeCombination *res = (Z_AttributeCombination *)
1292         odr_malloc (eh->o, sizeof(*res));
1293     data1_node *c;
1294     int i = 0;
1295
1296     res->num_occurrences = 0;
1297     res->occurrences = 0;
1298     for (c = n->child; c; c = c->next)
1299         if (is_numeric_tag (eh, c) == 719)
1300             (res->num_occurrences)++;
1301     if (res->num_occurrences)
1302     {
1303         res->occurrences = (Z_AttributeOccurrence **)
1304             odr_malloc (eh->o, res->num_occurrences * sizeof(*res->occurrences));
1305     }
1306     for (c = n->child; c; c = c->next)
1307         if (is_numeric_tag(eh, c) == 719)
1308             res->occurrences[i++] = f_attributeOccurrence (eh, c);
1309     assert (res->num_occurrences);
1310     return res;
1311 }
1312
1313 Z_AttributeCombinations *f_attributeCombinations (ExpHandle *eh, data1_node *n)
1314 {
1315     Z_AttributeCombinations *res = (Z_AttributeCombinations *)
1316         odr_malloc (eh->o, sizeof(*res));
1317     data1_node *c;
1318     res->defaultAttributeSet = 0;
1319     res->num_legalCombinations = 0;
1320     res->legalCombinations = 0;
1321
1322     for (c = n->child; c; c = c->next)
1323     {
1324         int i = 0;
1325         switch (is_numeric_tag (eh, c))
1326         {
1327         case 1000:
1328             res->defaultAttributeSet = f_oid (eh, c, CLASS_ATTSET);
1329             break;
1330         case 717:
1331             for (n = c->child; n; n = n->next)
1332             {
1333                 if (is_numeric_tag(eh, n) != 718)
1334                     continue;
1335                 (res->num_legalCombinations)++;
1336             }
1337             if (res->num_legalCombinations)
1338                 res->legalCombinations =
1339                     (Z_AttributeCombination **)
1340                     odr_malloc (eh->o, res->num_legalCombinations
1341                                 * sizeof(*res->legalCombinations));
1342             for (n = c->child; n; n = n->next)
1343             {
1344                 if (is_numeric_tag(eh, n) != 718)
1345                     continue;
1346                 res->legalCombinations[i++] = f_attributeCombination (eh, n);
1347             }
1348             break;
1349         }
1350     }
1351     assert (res->num_legalCombinations);
1352     return res;
1353 }
1354
1355 Z_AttributeDetails *f_attributeDetails (ExpHandle *eh, data1_node *n)
1356 {
1357     Z_AttributeDetails *res = (Z_AttributeDetails *)
1358         odr_malloc(eh->o, sizeof(*res));
1359     data1_node *c;
1360
1361     res->commonInfo = 0;
1362     res->databaseName = 0;
1363     res->num_attributesBySet = 0;
1364     res->attributesBySet = NULL;
1365     res->attributeCombinations = NULL;
1366
1367     for (c = n->child; c; c = c->next)
1368     {
1369         int i = 0;
1370         switch (is_numeric_tag (eh, c))
1371         {
1372         case 600: res->commonInfo = f_commonInfo(eh, c); break;
1373         case 102: res->databaseName = f_string (eh, c); break;
1374         case 700:
1375             for (n = c->child; n; n = n->next)
1376             {
1377                 if (is_numeric_tag(eh, n) != 701)
1378                     continue;
1379                 (res->num_attributesBySet)++;
1380             }
1381             if (res->num_attributesBySet)
1382                 res->attributesBySet =
1383                     (Z_AttributeSetDetails **)
1384                     odr_malloc (eh->o, res->num_attributesBySet
1385                                 * sizeof(*res->attributesBySet));
1386             for (n = c->child; n; n = n->next)
1387             {
1388                 if (is_numeric_tag(eh, n) != 701)
1389                     continue;
1390                 res->attributesBySet[i++] = f_attributeSetDetails (eh, n);
1391             }
1392             break;
1393         case 716:
1394             res->attributeCombinations = f_attributeCombinations (eh, c);
1395             break;
1396         }
1397     }
1398     return res;
1399 }
1400
1401 Z_ExplainRecord *data1_nodetoexplain (data1_handle dh, data1_node *n,
1402                                       int select, ODR o)
1403 {
1404     ExpHandle eh;
1405     Z_ExplainRecord *res = (Z_ExplainRecord *)odr_malloc(o, sizeof(*res));
1406
1407     eh.dh = dh;
1408     eh.select = select;
1409     eh.o = o;
1410     eh.false_value = (int *)odr_malloc(eh.o, sizeof(eh.false_value));
1411     *eh.false_value = 0;
1412     eh.true_value = (int *)odr_malloc(eh.o, sizeof(eh.true_value));
1413     *eh.true_value = 1;
1414
1415     assert(n->which == DATA1N_root);
1416     if (strcmp(n->u.root.type, "explain"))
1417     {
1418         logf(LOG_WARN, "Attempt to convert a non-Explain record");
1419         return 0;
1420     }
1421     for (n = n->child; n; n = n->next)
1422     {
1423         switch (is_numeric_tag (&eh, n))
1424         {
1425         case 1:
1426             res->which = Z_Explain_categoryList;
1427             if (!(res->u.categoryList = f_categoryList(&eh, n)))
1428                 return 0;
1429             return res;     
1430         case 2:
1431             res->which = Z_Explain_targetInfo;
1432             if (!(res->u.targetInfo = f_targetInfo(&eh, n)))
1433                 return 0;
1434             return res;
1435         case 3:
1436             res->which = Z_Explain_databaseInfo;
1437             if (!(res->u.databaseInfo = f_databaseInfo(&eh, n)))
1438                 return 0;
1439             return res;
1440         case 7:
1441             res->which = Z_Explain_attributeSetInfo;
1442             if (!(res->u.attributeSetInfo = f_attributeSetInfo(&eh, n)))
1443                 return 0;
1444             return res;     
1445         case 10:
1446             res->which = Z_Explain_attributeDetails;
1447             if (!(res->u.attributeDetails = f_attributeDetails(&eh, n)))
1448                 return 0;
1449             return res;
1450         }
1451     }
1452     logf(LOG_WARN, "No category in Explain record");
1453     return 0;
1454 }