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