Fix documentation of of chr's equivalent directive ZEB-672
[idzebra-moved-to-github.git] / data1 / d1_expout.c
1 /* This file is part of the Zebra server.
2    Copyright (C) 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 #if HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include <assert.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include <yaz/log.h>
32 #include <yaz/proto.h>
33 #include <yaz/oid_db.h>
34 #include <yaz/snprintf.h>
35 #include <idzebra/data1.h>
36
37 typedef struct {
38     data1_handle dh;
39     ODR o;
40     int select;
41
42     bool_t *false_value;
43     bool_t *true_value;
44 } ExpHandle;
45
46 static int is_numeric_tag (ExpHandle *eh, data1_node *c)
47 {
48     if (!c || c->which != DATA1N_tag)
49         return 0;
50     if (!c->u.tag.element)
51     {
52         yaz_log(YLOG_WARN, "Tag %s is local", c->u.tag.tag);
53         return 0;
54     }
55     if (c->u.tag.element->tag->which != DATA1T_numeric)
56     {
57         yaz_log(YLOG_WARN, "Tag %s is not numeric", c->u.tag.tag);
58         return 0;
59     }
60     if (eh->select && !c->u.tag.node_selected)
61         return 0;
62     return c->u.tag.element->tag->value.numeric;
63 }
64
65 static int is_data_tag (ExpHandle *eh, data1_node *c)
66 {
67     if (!c || c->which != DATA1N_data)
68         return 0;
69     if (eh->select && !c->u.tag.node_selected)
70         return 0;
71     return 1;
72 }
73
74 static Odr_int *f_integer(ExpHandle *eh, data1_node *c)
75 {
76     char intbuf[64];
77
78     c = c->child;
79     if (!is_data_tag (eh, c) || c->u.data.len >= sizeof(intbuf))
80         return 0;
81     sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
82     return odr_intdup(eh->o, atoi(intbuf));
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 = (Odr_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 Odr_int *f_recordCount(ExpHandle *eh, data1_node *c, int *which)
392 {
393     int *wp = which;
394     char intbuf[64];
395
396     c = c->child;
397     if (!is_numeric_tag (eh, c))
398         return 0;
399     if (c->u.tag.element->tag->value.numeric == 210)
400         *wp = Z_DatabaseInfo_actualNumber;
401     else if (c->u.tag.element->tag->value.numeric == 211)
402         *wp = Z_DatabaseInfo_approxNumber;
403     else
404         return 0;
405     if (!c->child || c->child->which != DATA1N_data ||
406         c->child->u.data.len >= sizeof(intbuf))
407         return 0;
408     sprintf(intbuf, "%.*s", c->child->u.data.len, c->child->u.data.data);
409     return odr_intdup(eh->o, atoi(intbuf));
410 }
411
412 static Z_ContactInfo *f_contactInfo(ExpHandle *eh, data1_node *n)
413 {
414     Z_ContactInfo *res = (Z_ContactInfo *)
415         odr_malloc (eh->o, sizeof(*res));
416     data1_node *c;
417
418     res->name = 0;
419     res->description = 0;
420     res->address = 0;
421     res->email = 0;
422     res->phone = 0;
423
424     for (c = n->child; c; c = c->next)
425     {
426         switch (is_numeric_tag (eh, c))
427         {
428         case 102: res->name = f_string (eh, c); break;
429         case 113: res->description = f_humstring (eh, c); break;
430         case 127: res->address = f_humstring (eh, c); break;
431         case 128: res->email = f_string (eh, c); break;
432         case 129: res->phone = f_string (eh, c); break;
433         }
434     }
435     return res;
436 }
437
438 static Z_DatabaseList *f_databaseList(ExpHandle *eh, data1_node *n)
439 {
440     data1_node *c;
441     Z_DatabaseList *res;
442     int i = 0;
443
444     for (c = n->child; c; c = c->next)
445     {
446         if (!is_numeric_tag (eh, c) != 102)
447             continue;
448         ++i;
449     }
450     if (!i)
451         return NULL;
452
453     res = (Z_DatabaseList *)odr_malloc (eh->o, sizeof(*res));
454
455     res->num_databases = i;
456     res->databases = (char **)odr_malloc (eh->o, sizeof(*res->databases) * i);
457     i = 0;
458     for (c = n->child; c; c = c->next)
459     {
460         if (!is_numeric_tag (eh, c) != 102)
461             continue;
462         res->databases[i++] = f_string (eh, c);
463     }
464     return res;
465 }
466
467 static Z_NetworkAddressIA *f_networkAddressIA(ExpHandle *eh, data1_node *n)
468 {
469     Z_NetworkAddressIA *res = (Z_NetworkAddressIA *)
470         odr_malloc (eh->o, sizeof(*res));
471     data1_node *c;
472
473     res->hostAddress = 0;
474     res->port = 0;
475
476     for (c = n->child; c; c = c->next)
477     {
478         switch (is_numeric_tag (eh, c))
479         {
480         case 121: res->hostAddress = f_string (eh, c); break;
481         case 122: res->port = f_integer (eh, c); break;
482         }
483     }
484     return res;
485 }
486
487 static Z_NetworkAddressOther *f_networkAddressOther(ExpHandle *eh,
488                                                     data1_node *n)
489 {
490     Z_NetworkAddressOther *res = (Z_NetworkAddressOther *)
491         odr_malloc (eh->o, sizeof(*res));
492     data1_node *c;
493
494     res->type = 0;
495     res->address = 0;
496
497     for (c = n->child; c; c = c->next)
498     {
499         switch (is_numeric_tag (eh, c))
500         {
501         case 124: res->type = f_string (eh, c); break;
502         case 121: res->address = f_string (eh, c); break;
503         }
504     }
505     return res;
506 }
507
508 static Z_NetworkAddress **f_networkAddresses(ExpHandle *eh, data1_node *n,
509                                              int *num)
510 {
511     Z_NetworkAddress **res = NULL;
512     data1_node *c;
513     int i = 0;
514
515     *num = 0;
516     for (c = n->child; c; c = c->next)
517     {
518         switch (is_numeric_tag (eh, c))
519         {
520         case 120:
521         case 123:
522             (*num)++;
523             break;
524         }
525     }
526
527     if (*num)
528         res = (Z_NetworkAddress **) odr_malloc (eh->o, sizeof(*res) * (*num));
529
530     for (c = n->child; c; c = c->next)
531     {
532         switch (is_numeric_tag (eh, c))
533         {
534         case 120:
535             res[i] = (Z_NetworkAddress *) odr_malloc (eh->o, sizeof(**res));
536             res[i]->which = Z_NetworkAddress_iA;
537             res[i]->u.internetAddress = f_networkAddressIA(eh, c);
538             i++;
539             break;
540         case 123:
541             res[i] = (Z_NetworkAddress *) odr_malloc (eh->o, sizeof(**res));
542             res[i]->which = Z_NetworkAddress_other;
543             res[i]->u.other = f_networkAddressOther(eh, c);
544             i++;
545             break;
546         }
547     }
548     return res;
549 }
550
551 static Z_CategoryInfo *f_categoryInfo(ExpHandle *eh, data1_node *n)
552 {
553     Z_CategoryInfo *res = (Z_CategoryInfo *)odr_malloc(eh->o, sizeof(*res));
554     data1_node *c;
555
556     res->category = 0;
557     res->originalCategory = 0;
558     res->description = 0;
559     res->asn1Module = 0;
560     for (c = n->child; c; c = c->next)
561     {
562         switch (is_numeric_tag (eh, c))
563         {
564         case 102: res->category = f_string(eh, c); break;
565         case 302: res->originalCategory = f_string(eh, c); break;
566         case 113: res->description = f_humstring(eh, c); break;
567         case 303: res->asn1Module = f_string (eh, c); break;
568         }
569     }
570     return res;
571 }
572
573 static Z_CategoryList *f_categoryList(ExpHandle *eh, data1_node *n)
574 {
575     Z_CategoryList *res = (Z_CategoryList *)odr_malloc(eh->o, sizeof(*res));
576     data1_node *c;
577
578     res->commonInfo = 0;
579     res->num_categories = 0;
580     res->categories = NULL;
581
582     for (c = n->child; c; c = c->next)
583     {
584         int i = 0;
585
586         switch (is_numeric_tag (eh, c))
587         {
588         case 600: res->commonInfo = f_commonInfo(eh, c); break;
589         case 300:
590             for (n = c->child; n; n = n->next)
591             {
592                 if (is_numeric_tag(eh, n) != 301)
593                     continue;
594                 (res->num_categories)++;
595             }
596             if (res->num_categories)
597                 res->categories =
598                     (Z_CategoryInfo **)odr_malloc (eh->o, res->num_categories
599                                                    * sizeof(*res->categories));
600             for (n = c->child; n; n = n->next)
601             {
602                 if (is_numeric_tag(eh, n) != 301)
603                     continue;
604                 res->categories[i++] = f_categoryInfo (eh, n);
605             }
606             break;
607         }
608     }
609     assert (res->num_categories && res->categories);
610     return res;
611 }
612
613 static Z_TargetInfo *f_targetInfo(ExpHandle *eh, data1_node *n)
614 {
615     Z_TargetInfo *res = (Z_TargetInfo *)odr_malloc(eh->o, sizeof(*res));
616     data1_node *c;
617
618     res->commonInfo = 0;
619     res->name = 0;
620     res->recentNews = 0;
621     res->icon = 0;
622     res->namedResultSets = 0;
623     res->multipleDBsearch = 0;
624     res->maxResultSets = 0;
625     res->maxResultSize = 0;
626     res->maxTerms = 0;
627     res->timeoutInterval = 0;
628     res->welcomeMessage = 0;
629     res->contactInfo = 0;
630     res->description = 0;
631     res->num_nicknames = 0;
632     res->nicknames = 0;
633     res->usageRest = 0;
634     res->paymentAddr = 0;
635     res->hours = 0;
636     res->num_dbCombinations = 0;
637     res->dbCombinations = 0;
638     res->num_addresses = 0;
639     res->addresses = 0;
640     res->num_languages = 0;
641     res->languages = NULL;
642     res->commonAccessInfo = 0;
643
644     for (c = n->child; c; c = c->next)
645     {
646         int i = 0;
647
648         switch (is_numeric_tag (eh, c))
649         {
650         case 600: res->commonInfo = f_commonInfo(eh, c); break;
651         case 102: res->name = f_string(eh, c); break;
652         case 103: res->recentNews = f_humstring(eh, c); break;
653         case 104: res->icon = NULL; break; /* fix */
654         case 105: res->namedResultSets = f_bool(eh, c); break;
655         case 106: res->multipleDBsearch = f_bool(eh, c); break;
656         case 107: res->maxResultSets = f_integer(eh, c); break;
657         case 108: res->maxResultSize = f_integer(eh, c); break;
658         case 109: res->maxTerms = f_integer(eh, c); break;
659         case 110: res->timeoutInterval = f_intunit(eh, c); break;
660         case 111: res->welcomeMessage = f_humstring(eh, c); break;
661         case 112: res->contactInfo = f_contactInfo(eh, c); break;
662         case 113: res->description = f_humstring(eh, c); break;
663         case 114:
664             res->num_nicknames = 0;
665             for (n = c->child; n; n = n->next)
666             {
667                 if (is_numeric_tag(eh, n) != 102)
668                     continue;
669                 (res->num_nicknames)++;
670             }
671             if (res->num_nicknames)
672                 res->nicknames =
673                     (char **)odr_malloc (eh->o, res->num_nicknames
674                                 * sizeof(*res->nicknames));
675             for (n = c->child; n; n = n->next)
676             {
677                 if (is_numeric_tag(eh, n) != 102)
678                     continue;
679                 res->nicknames[i++] = f_string (eh, n);
680             }
681             break;
682         case 115: res->usageRest = f_humstring(eh, c); break;
683         case 116: res->paymentAddr = f_humstring(eh, c); break;
684         case 117: res->hours = f_humstring(eh, c); break;
685         case 118:
686             res->num_dbCombinations = 0;
687             for (n = c->child; n; n = n->next)
688             {
689                 if (!is_numeric_tag(eh, n) != 605)
690                     continue;
691                 (res->num_dbCombinations)++;
692             }
693             if (res->num_dbCombinations)
694                 res->dbCombinations =
695                     (Z_DatabaseList **)odr_malloc (eh->o, res->num_dbCombinations
696                                 * sizeof(*res->dbCombinations));
697             for (n = c->child; n; n = n->next)
698             {
699                 if (!is_numeric_tag(eh, n) != 605)
700                     continue;
701                 res->dbCombinations[i++] = f_databaseList (eh, n);
702             }
703             break;
704         case 119:
705             res->addresses =
706                 f_networkAddresses (eh, c, &res->num_addresses);
707             break;
708         case 125:
709             res->num_languages = 0;
710             for (n = c->child; n; n = n->next)
711             {
712                 if (!is_numeric_tag(eh, n) != 126)
713                     continue;
714                 (res->num_languages)++;
715             }
716             if (res->num_languages)
717                 res->languages = (char **)
718                     odr_malloc (eh->o, res->num_languages *
719                                 sizeof(*res->languages));
720             for (n = c->child; n; n = n->next)
721             {
722                 if (!is_numeric_tag(eh, n) != 126)
723                     continue;
724                 res->languages[i++] = f_string (eh, n);
725             }
726             break;
727         case 500: res->commonAccessInfo = f_accessInfo(eh, c); break;
728         }
729     }
730     if (!res->namedResultSets)
731         res->namedResultSets = eh->false_value;
732     if (!res->multipleDBsearch)
733         res->multipleDBsearch = eh->false_value;
734     return res;
735 }
736
737 static Z_DatabaseInfo *f_databaseInfo(ExpHandle *eh, data1_node *n)
738 {
739     Z_DatabaseInfo *res = (Z_DatabaseInfo *)odr_malloc(eh->o, sizeof(*res));
740     data1_node *c;
741
742     res->commonInfo = 0;
743     res->name = 0;
744     res->explainDatabase = 0;
745     res->num_nicknames = 0;
746     res->nicknames = 0;
747     res->icon = 0;
748     res->userFee = 0;
749     res->available = 0;
750     res->titleString = 0;
751     res->num_keywords = 0;
752     res->keywords = 0;
753     res->description = 0;
754     res->associatedDbs = 0;
755     res->subDbs = 0;
756     res->disclaimers = 0;
757     res->news = 0;
758     res->u.actualNumber = 0;
759     res->defaultOrder = 0;
760     res->avRecordSize = 0;
761     res->maxRecordSize = 0;
762     res->hours = 0;
763     res->bestTime = 0;
764     res->lastUpdate = 0;
765     res->updateInterval = 0;
766     res->coverage = 0;
767     res->proprietary = 0;
768     res->copyrightText = 0;
769     res->copyrightNotice = 0;
770     res->producerContactInfo = 0;
771     res->supplierContactInfo = 0;
772     res->submissionContactInfo = 0;
773     res->accessInfo = 0;
774
775     for (c = n->child; c; c = c->next)
776     {
777         int i = 0;
778
779         switch (is_numeric_tag (eh, c))
780         {
781         case 600: res->commonInfo = f_commonInfo(eh, c); break;
782         case 102: res->name = f_string(eh, c); break;
783         case 226: res->explainDatabase = odr_nullval(); break;
784         case 114:
785             res->num_nicknames = 0;
786             for (n = c->child; n; n = n->next)
787             {
788                 if (!is_numeric_tag(eh, n) ||
789                     n->u.tag.element->tag->value.numeric != 102)
790                     continue;
791                 (res->num_nicknames)++;
792             }
793             if (res->num_nicknames)
794                 res->nicknames =
795                     (char **)odr_malloc (eh->o, res->num_nicknames
796                                 * sizeof(*res->nicknames));
797             for (n = c->child; n; n = n->next)
798             {
799                 if (!is_numeric_tag(eh, n) ||
800                     n->u.tag.element->tag->value.numeric != 102)
801                     continue;
802                 res->nicknames[i++] = f_string (eh, n);
803             }
804             break;
805         case 104: res->icon = 0; break;      /* fix */
806         case 201: res->userFee = f_bool(eh, c); break;
807         case 202: res->available = f_bool(eh, c); break;
808         case 203: res->titleString = f_humstring(eh, c); break;
809         case 227:
810             res->num_keywords = 0;
811             for (n = c->child; n; n = n->next)
812             {
813                 if (!is_numeric_tag(eh, n) != 1000)
814                     continue;
815                 (res->num_keywords)++;
816             }
817             if (res->num_keywords)
818                 res->keywords =
819                     (Z_HumanString **)odr_malloc (eh->o, res->num_keywords
820                                 * sizeof(*res->keywords));
821             for (n = c->child; n; n = n->next)
822             {
823                 if (!is_numeric_tag(eh, n) != 1000)
824                     continue;
825                 res->keywords[i++] = f_humstring (eh, n);
826             }
827             break;
828         case 113: res->description = f_humstring(eh, c); break;
829         case 205:
830             res->associatedDbs = f_databaseList (eh, c);
831             break;
832         case 206:
833             res->subDbs = f_databaseList (eh, c);
834             break;
835         case 207: res->disclaimers = f_humstring(eh, c); break;
836         case 103: res->news = f_humstring(eh, c); break;
837         case 209: res->u.actualNumber =
838                       f_recordCount(eh, c, &res->which); break;
839         case 212: res->defaultOrder = f_humstring(eh, c); break;
840         case 213: res->avRecordSize = f_integer(eh, c); break;
841         case 214: res->maxRecordSize = f_integer(eh, c); break;
842         case 215: res->hours = f_humstring(eh, c); break;
843         case 216: res->bestTime = f_humstring(eh, c); break;
844         case 217: res->lastUpdate = f_string(eh, c); break;
845         case 218: res->updateInterval = f_intunit(eh, c); break;
846         case 219: res->coverage = f_humstring(eh, c); break;
847         case 220: res->proprietary = f_bool(eh, c); break;
848         case 221: res->copyrightText = f_humstring(eh, c); break;
849         case 222: res->copyrightNotice = f_humstring(eh, c); break;
850         case 223: res->producerContactInfo = f_contactInfo(eh, c); break;
851         case 224: res->supplierContactInfo = f_contactInfo(eh, c); break;
852         case 225: res->submissionContactInfo = f_contactInfo(eh, c); break;
853         case 500: res->accessInfo = f_accessInfo(eh, c); break;
854         }
855     }
856     if (!res->userFee)
857         res->userFee = eh->false_value;
858     if (!res->available)
859         res->available = eh->true_value;
860     return res;
861 }
862
863 Z_StringOrNumeric *f_stringOrNumeric (ExpHandle *eh, data1_node *n)
864 {
865     Z_StringOrNumeric *res = (Z_StringOrNumeric *)
866         odr_malloc (eh->o, sizeof(*res));
867     data1_node *c;
868     for (c = n->child; c; c = c->next)
869     {
870         switch (is_numeric_tag (eh, c))
871         {
872         case 1001:
873             res->which = Z_StringOrNumeric_string;
874             res->u.string = f_string (eh, c);
875             break;
876         case 1002:
877             res->which = Z_StringOrNumeric_numeric;
878             res->u.numeric = f_integer (eh, c);
879             break;
880         }
881     }
882     return res;
883 }
884
885 Z_AttributeDescription *f_attributeDescription (
886     ExpHandle *eh, data1_node *n)
887 {
888     Z_AttributeDescription *res = (Z_AttributeDescription *)
889         odr_malloc(eh->o, sizeof(*res));
890     data1_node *c;
891     int i = 0;
892
893     res->name = 0;
894     res->description = 0;
895     res->attributeValue = 0;
896     res->num_equivalentAttributes = 0;
897     res->equivalentAttributes = 0;
898
899     for (c = n->child; c; c = c->next)
900     {
901         switch (is_numeric_tag (eh, c))
902         {
903         case 102: res->name = f_string (eh, c); break;
904         case 113: res->description = f_humstring (eh, c); break;
905         case 710: res->attributeValue = f_stringOrNumeric (eh, c); break;
906         case 752: (res->num_equivalentAttributes++); break;
907         }
908     }
909     if (res->num_equivalentAttributes)
910         res->equivalentAttributes = (Z_StringOrNumeric **)
911             odr_malloc (eh->o, sizeof(*res->equivalentAttributes) *
912                         res->num_equivalentAttributes);
913     for (c = n->child; c; c = c->next)
914         if (is_numeric_tag (eh, c) == 752)
915             res->equivalentAttributes[i++] = f_stringOrNumeric (eh, c);
916     return res;
917 }
918
919 Z_AttributeType *f_attributeType (ExpHandle *eh, data1_node *n)
920 {
921     Z_AttributeType *res = (Z_AttributeType *)
922         odr_malloc(eh->o, sizeof(*res));
923     data1_node *c;
924
925     res->name = 0;
926     res->description = 0;
927     res->attributeType = 0;
928     res->num_attributeValues = 0;
929     res->attributeValues = 0;
930
931     for (c = n->child; c; c = c->next)
932     {
933         int i = 0;
934         switch (is_numeric_tag (eh, c))
935         {
936         case 102: res->name = f_string (eh, c); break;
937         case 113: res->description = f_humstring (eh, c); break;
938         case 704: res->attributeType = f_integer (eh, c); break;
939         case 708:
940             for (n = c->child; n; n = n->next)
941             {
942                 if (is_numeric_tag(eh, n) != 709)
943                     continue;
944                 (res->num_attributeValues)++;
945             }
946             if (res->num_attributeValues)
947                 res->attributeValues = (Z_AttributeDescription **)
948                     odr_malloc (eh->o, res->num_attributeValues
949                                 * sizeof(*res->attributeValues));
950             for (n = c->child; n; n = n->next)
951             {
952                 if (is_numeric_tag(eh, n) != 709)
953                     continue;
954                 res->attributeValues[i++] = f_attributeDescription (eh, n);
955             }
956             break;
957         }
958     }
959     return res;
960 }
961
962 Z_AttributeSetInfo *f_attributeSetInfo (ExpHandle *eh, data1_node *n)
963 {
964     Z_AttributeSetInfo *res = (Z_AttributeSetInfo *)
965         odr_malloc(eh->o, sizeof(*res));
966     data1_node *c;
967
968     res->commonInfo = 0;
969     res->attributeSet = 0;
970     res->name = 0;
971     res->num_attributes = 0;
972     res->attributes = 0;
973     res->description = 0;
974     for (c = n->child; c; c = c->next)
975     {
976         int i = 0;
977         switch (is_numeric_tag (eh, c))
978         {
979         case 600: res->commonInfo = f_commonInfo (eh, c); break;
980         case 1000: res->attributeSet = f_oid (eh, c, CLASS_ATTSET); break;
981         case 102: res->name = f_string (eh, c); break;
982         case 750:
983             for (n = c->child; n; n = n->next)
984             {
985                 if (is_numeric_tag(eh, n) != 751)
986                     continue;
987                 (res->num_attributes)++;
988             }
989             if (res->num_attributes)
990                 res->attributes = (Z_AttributeType **)
991                     odr_malloc (eh->o, res->num_attributes
992                                 * sizeof(*res->attributes));
993             for (n = c->child; n; n = n->next)
994             {
995                 if (is_numeric_tag(eh, n) != 751)
996                     continue;
997                 res->attributes[i++] = f_attributeType (eh, n);
998             }
999             break;
1000         case 113: res->description = f_humstring (eh, c); break;
1001         }
1002     }
1003     return res;
1004 }
1005
1006 Z_OmittedAttributeInterpretation *f_omittedAttributeInterpretation (
1007     ExpHandle *eh, data1_node *n)
1008 {
1009     Z_OmittedAttributeInterpretation *res = (Z_OmittedAttributeInterpretation*)
1010         odr_malloc (eh->o, sizeof(*res));
1011     data1_node *c;
1012
1013     res->defaultValue = 0;
1014     res->defaultDescription = 0;
1015     for (c = n->child; c; c = c->next)
1016     {
1017         switch (is_numeric_tag (eh, c))
1018         {
1019         case 706:
1020             res->defaultValue = f_stringOrNumeric (eh, c);
1021             break;
1022         case 113:
1023             res->defaultDescription = f_humstring(eh, c);
1024             break;
1025         }
1026     }
1027     return res;
1028 }
1029
1030 Z_AttributeValue *f_attributeValue (ExpHandle *eh, data1_node *n)
1031 {
1032     Z_AttributeValue *res = (Z_AttributeValue *)
1033         odr_malloc (eh->o, sizeof(*res));
1034     data1_node *c;
1035
1036     res->value = 0;
1037     res->description = 0;
1038     res->num_subAttributes = 0;
1039     res->subAttributes = 0;
1040     res->num_superAttributes = 0;
1041     res->superAttributes = 0;
1042     res->partialSupport = 0;
1043     for (c = n->child; c; c = c->next)
1044     {
1045         int i = 0;
1046         switch (is_numeric_tag (eh, c))
1047         {
1048         case 710:
1049             res->value = f_stringOrNumeric (eh, c);  break;
1050         case 113:
1051             res->description = f_humstring (eh, c); break;
1052         case 712:
1053             for (n = c->child; n; n = n->next)
1054             {
1055                 if (is_numeric_tag(eh, n) != 713)
1056                     continue;
1057                 (res->num_subAttributes)++;
1058             }
1059             if (res->num_subAttributes)
1060                 res->subAttributes =
1061                     (Z_StringOrNumeric **)
1062                     odr_malloc (eh->o, res->num_subAttributes
1063                                 * sizeof(*res->subAttributes));
1064             for (n = c->child; n; n = n->next)
1065             {
1066                 if (is_numeric_tag(eh, n) != 713)
1067                     continue;
1068                 res->subAttributes[i++] = f_stringOrNumeric (eh, n);
1069             }
1070             break;
1071         case 714:
1072             for (n = c->child; n; n = n->next)
1073             {
1074                 if (is_numeric_tag(eh, n) != 715)
1075                     continue;
1076                 (res->num_superAttributes)++;
1077             }
1078             if (res->num_superAttributes)
1079                 res->superAttributes =
1080                     (Z_StringOrNumeric **)
1081                     odr_malloc (eh->o, res->num_superAttributes
1082                                 * sizeof(*res->superAttributes));
1083             for (n = c->child; n; n = n->next)
1084             {
1085                 if (is_numeric_tag(eh, n) != 715)
1086                     continue;
1087                 res->superAttributes[i++] = f_stringOrNumeric (eh, n);
1088             }
1089             break;
1090         case 711:
1091             res->partialSupport = odr_nullval ();
1092             break;
1093         }
1094     }
1095     return res;
1096 }
1097
1098 Z_AttributeTypeDetails *f_attributeTypeDetails (ExpHandle *eh, data1_node *n)
1099 {
1100     Z_AttributeTypeDetails *res = (Z_AttributeTypeDetails *)
1101         odr_malloc(eh->o, sizeof(*res));
1102     data1_node *c;
1103     res->attributeType = 0;
1104     res->defaultIfOmitted = 0;
1105     res->num_attributeValues = 0;
1106     res->attributeValues = 0;
1107     for (c = n->child; c; c = c->next)
1108     {
1109         int i = 0;
1110         switch (is_numeric_tag (eh, c))
1111         {
1112         case 704: res->attributeType = f_integer (eh, c); break;
1113         case 705:
1114             res->defaultIfOmitted = f_omittedAttributeInterpretation (eh, c);
1115             break;
1116         case 708:
1117             for (n = c->child; n; n = n->next)
1118             {
1119                 if (is_numeric_tag(eh, n) != 709)
1120                     continue;
1121                 (res->num_attributeValues)++;
1122             }
1123             if (res->num_attributeValues)
1124                 res->attributeValues =
1125                     (Z_AttributeValue **)
1126                     odr_malloc (eh->o, res->num_attributeValues
1127                                 * sizeof(*res->attributeValues));
1128             for (n = c->child; n; n = n->next)
1129             {
1130                 if (is_numeric_tag(eh, n) != 709)
1131                     continue;
1132                 res->attributeValues[i++] = f_attributeValue (eh, n);
1133             }
1134             break;
1135         }
1136     }
1137     return res;
1138 }
1139
1140 Z_AttributeSetDetails *f_attributeSetDetails (ExpHandle *eh, data1_node *n)
1141 {
1142     Z_AttributeSetDetails *res = (Z_AttributeSetDetails *)
1143         odr_malloc(eh->o, sizeof(*res));
1144     data1_node *c;
1145
1146     res->attributeSet = 0;
1147     res->num_attributesByType = 0;
1148     res->attributesByType = 0;
1149     for (c = n->child; c; c = c->next)
1150     {
1151         int i = 0;
1152         switch (is_numeric_tag (eh, c))
1153         {
1154         case 1000: res->attributeSet = f_oid(eh, c, CLASS_ATTSET); break;
1155         case 702:
1156             for (n = c->child; n; n = n->next)
1157             {
1158                 if (is_numeric_tag(eh, n) != 703)
1159                     continue;
1160                 (res->num_attributesByType)++;
1161             }
1162             if (res->num_attributesByType)
1163                 res->attributesByType =
1164                     (Z_AttributeTypeDetails **)
1165                     odr_malloc (eh->o, res->num_attributesByType
1166                                 * sizeof(*res->attributesByType));
1167             for (n = c->child; n; n = n->next)
1168             {
1169                 if (is_numeric_tag(eh, n) != 703)
1170                     continue;
1171                 res->attributesByType[i++] = f_attributeTypeDetails (eh, n);
1172             }
1173             break;
1174         }
1175     }
1176     return res;
1177 }
1178
1179 Z_AttributeValueList *f_attributeValueList (ExpHandle *eh, data1_node *n)
1180 {
1181     Z_AttributeValueList *res = (Z_AttributeValueList *)
1182         odr_malloc (eh->o, sizeof(*res));
1183     data1_node *c;
1184     int i = 0;
1185
1186     res->num_attributes = 0;
1187     res->attributes = 0;
1188     for (c = n->child; c; c = c->next)
1189         if (is_numeric_tag (eh, c) == 710)
1190             (res->num_attributes)++;
1191     if (res->num_attributes)
1192     {
1193         res->attributes = (Z_StringOrNumeric **)
1194             odr_malloc (eh->o, res->num_attributes * sizeof(*res->attributes));
1195     }
1196     for (c = n->child; c; c = c->next)
1197         if (is_numeric_tag(eh, c) == 710)
1198             res->attributes[i++] = f_stringOrNumeric (eh, c);
1199     return res;
1200 }
1201
1202 Z_AttributeOccurrence *f_attributeOccurrence (ExpHandle *eh, data1_node *n)
1203 {
1204     Z_AttributeOccurrence *res = (Z_AttributeOccurrence *)
1205         odr_malloc (eh->o, sizeof(*res));
1206     data1_node *c;
1207
1208     res->attributeSet = 0;
1209     res->attributeType = 0;
1210     res->mustBeSupplied = 0;
1211     res->which = Z_AttributeOcc_any_or_none;
1212     res->attributeValues.any_or_none = odr_nullval ();
1213
1214     for (c = n->child; c; c = c->next)
1215     {
1216         switch (is_numeric_tag (eh, c))
1217         {
1218         case 1000:
1219             res->attributeSet = f_oid (eh, c, CLASS_ATTSET); break;
1220         case 704:
1221             res->attributeType = f_integer (eh, c); break;
1222         case 720:
1223             res->mustBeSupplied = odr_nullval (); break;
1224         case 721:
1225             res->which = Z_AttributeOcc_any_or_none;
1226             res->attributeValues.any_or_none = odr_nullval ();
1227             break;
1228         case 722:
1229             res->which = Z_AttributeOcc_specific;
1230             res->attributeValues.specific = f_attributeValueList (eh, c);
1231             break;
1232         }
1233     }
1234     return res;
1235 }
1236
1237 Z_AttributeCombination *f_attributeCombination (ExpHandle *eh, data1_node *n)
1238 {
1239     Z_AttributeCombination *res = (Z_AttributeCombination *)
1240         odr_malloc (eh->o, sizeof(*res));
1241     data1_node *c;
1242     int i = 0;
1243
1244     res->num_occurrences = 0;
1245     res->occurrences = 0;
1246     for (c = n->child; c; c = c->next)
1247         if (is_numeric_tag (eh, c) == 719)
1248             (res->num_occurrences)++;
1249     if (res->num_occurrences)
1250     {
1251         res->occurrences = (Z_AttributeOccurrence **)
1252             odr_malloc (eh->o, res->num_occurrences * sizeof(*res->occurrences));
1253     }
1254     for (c = n->child; c; c = c->next)
1255         if (is_numeric_tag(eh, c) == 719)
1256             res->occurrences[i++] = f_attributeOccurrence (eh, c);
1257     assert (res->num_occurrences);
1258     return res;
1259 }
1260
1261 Z_AttributeCombinations *f_attributeCombinations (ExpHandle *eh, data1_node *n)
1262 {
1263     Z_AttributeCombinations *res = (Z_AttributeCombinations *)
1264         odr_malloc (eh->o, sizeof(*res));
1265     data1_node *c;
1266     res->defaultAttributeSet = 0;
1267     res->num_legalCombinations = 0;
1268     res->legalCombinations = 0;
1269
1270     for (c = n->child; c; c = c->next)
1271     {
1272         int i = 0;
1273         switch (is_numeric_tag (eh, c))
1274         {
1275         case 1000:
1276             res->defaultAttributeSet = f_oid (eh, c, CLASS_ATTSET);
1277             break;
1278         case 717:
1279             for (n = c->child; n; n = n->next)
1280             {
1281                 if (is_numeric_tag(eh, n) != 718)
1282                     continue;
1283                 (res->num_legalCombinations)++;
1284             }
1285             if (res->num_legalCombinations)
1286                 res->legalCombinations =
1287                     (Z_AttributeCombination **)
1288                     odr_malloc (eh->o, res->num_legalCombinations
1289                                 * sizeof(*res->legalCombinations));
1290             for (n = c->child; n; n = n->next)
1291             {
1292                 if (is_numeric_tag(eh, n) != 718)
1293                     continue;
1294                 res->legalCombinations[i++] = f_attributeCombination (eh, n);
1295             }
1296             break;
1297         }
1298     }
1299     assert (res->num_legalCombinations);
1300     return res;
1301 }
1302
1303 Z_AttributeDetails *f_attributeDetails (ExpHandle *eh, data1_node *n)
1304 {
1305     Z_AttributeDetails *res = (Z_AttributeDetails *)
1306         odr_malloc(eh->o, sizeof(*res));
1307     data1_node *c;
1308
1309     res->commonInfo = 0;
1310     res->databaseName = 0;
1311     res->num_attributesBySet = 0;
1312     res->attributesBySet = NULL;
1313     res->attributeCombinations = NULL;
1314
1315     for (c = n->child; c; c = c->next)
1316     {
1317         int i = 0;
1318         switch (is_numeric_tag (eh, c))
1319         {
1320         case 600: res->commonInfo = f_commonInfo(eh, c); break;
1321         case 102: res->databaseName = f_string (eh, c); break;
1322         case 700:
1323             for (n = c->child; n; n = n->next)
1324             {
1325                 if (is_numeric_tag(eh, n) != 701)
1326                     continue;
1327                 (res->num_attributesBySet)++;
1328             }
1329             if (res->num_attributesBySet)
1330                 res->attributesBySet =
1331                     (Z_AttributeSetDetails **)
1332                     odr_malloc (eh->o, res->num_attributesBySet
1333                                 * sizeof(*res->attributesBySet));
1334             for (n = c->child; n; n = n->next)
1335             {
1336                 if (is_numeric_tag(eh, n) != 701)
1337                     continue;
1338                 res->attributesBySet[i++] = f_attributeSetDetails (eh, n);
1339             }
1340             break;
1341         case 716:
1342             res->attributeCombinations = f_attributeCombinations (eh, c);
1343             break;
1344         }
1345     }
1346     return res;
1347 }
1348
1349 Z_ExplainRecord *data1_nodetoexplain (data1_handle dh, data1_node *n,
1350                                       int select, ODR o)
1351 {
1352     ExpHandle eh;
1353     Z_ExplainRecord *res = (Z_ExplainRecord *)odr_malloc(o, sizeof(*res));
1354
1355     eh.dh = dh;
1356     eh.select = select;
1357     eh.o = o;
1358     eh.false_value = (int *)odr_malloc(eh.o, sizeof(eh.false_value));
1359     *eh.false_value = 0;
1360     eh.true_value = (int *)odr_malloc(eh.o, sizeof(eh.true_value));
1361     *eh.true_value = 1;
1362
1363     assert(n->which == DATA1N_root);
1364     if (strcmp(n->u.root.type, "explain"))
1365     {
1366         yaz_log(YLOG_WARN, "Attempt to convert a non-Explain record");
1367         return 0;
1368     }
1369     for (n = n->child; n; n = n->next)
1370     {
1371         switch (is_numeric_tag (&eh, n))
1372         {
1373         case 1:
1374             res->which = Z_Explain_categoryList;
1375             if (!(res->u.categoryList = f_categoryList(&eh, n)))
1376                 return 0;
1377             return res;
1378         case 2:
1379             res->which = Z_Explain_targetInfo;
1380             if (!(res->u.targetInfo = f_targetInfo(&eh, n)))
1381                 return 0;
1382             return res;
1383         case 3:
1384             res->which = Z_Explain_databaseInfo;
1385             if (!(res->u.databaseInfo = f_databaseInfo(&eh, n)))
1386                 return 0;
1387             return res;
1388         case 7:
1389             res->which = Z_Explain_attributeSetInfo;
1390             if (!(res->u.attributeSetInfo = f_attributeSetInfo(&eh, n)))
1391                 return 0;
1392             return res;
1393         case 10:
1394             res->which = Z_Explain_attributeDetails;
1395             if (!(res->u.attributeDetails = f_attributeDetails(&eh, n)))
1396                 return 0;
1397             return res;
1398         }
1399     }
1400     yaz_log(YLOG_WARN, "No category in Explain record");
1401     return 0;
1402 }
1403 /*
1404  * Local variables:
1405  * c-basic-offset: 4
1406  * c-file-style: "Stroustrup"
1407  * indent-tabs-mode: nil
1408  * End:
1409  * vim: shiftwidth=4 tabstop=8 expandtab
1410  */
1411