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