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