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