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