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