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