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