Fixed Makefile(s).
[yaz-moved-to-github.git] / retrieval / d1_expout.c
1 /*
2  * Copyright (c) 1995-1997, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  *
6  * $Log: d1_expout.c,v $
7  * Revision 1.7  1997-12-09 16:18:16  adam
8  * Work on EXPLAIN schema. First implementation of sub-schema facility
9  * in the *.abs files.
10  *
11  * Revision 1.6  1997/11/24 11:33:56  adam
12  * Using function odr_nullval() instead of global ODR_NULLVAL when
13  * appropriate.
14  *
15  * Revision 1.5  1997/11/19 10:30:06  adam
16  * More explain work.
17  *
18  * Revision 1.4  1997/11/18 09:51:08  adam
19  * Removed element num_children from data1_node. Minor changes in
20  * data1 to Explain.
21  *
22  * Revision 1.3  1997/09/17 12:10:36  adam
23  * YAZ version 1.4.
24  *
25  * Revision 1.2  1995/12/14 16:28:30  quinn
26  * More explain stuff.
27  *
28  * Revision 1.1  1995/12/14  11:09:51  quinn
29  * Work on Explain
30  *
31  *
32  */
33
34 #include <assert.h>
35 #include <string.h>
36 #include <stdlib.h>
37
38 #include <log.h>
39 #include <proto.h>
40 #include <data1.h>
41
42 typedef struct {
43     data1_handle dh;
44     ODR o;
45     int select;
46
47     bool_t *false_value;
48     bool_t *true_value;
49 } ExpHandle;
50
51 static int is_numeric_tag (ExpHandle *eh, data1_node *c)
52 {
53     if (!c || c->which != DATA1N_tag)
54         return 0;
55     if (!c->u.tag.element)
56     {
57         logf(LOG_WARN, "Tag %s is local", c->u.tag.tag);
58         return 0;
59     }
60     if (c->u.tag.element->tag->which != DATA1T_numeric)
61     {
62         logf(LOG_WARN, "Tag %s is not numeric", c->u.tag.tag);
63         return 0;
64     }
65     if (eh->select && !c->u.tag.node_selected)
66         return 0;
67     return c->u.tag.element->tag->value.numeric;
68 }
69
70 static int is_data_tag (ExpHandle *eh, data1_node *c)
71 {
72     if (!c || c->which != DATA1N_data)
73         return 0;
74     if (eh->select && !c->u.tag.node_selected)
75         return 0;
76     return 1;
77 }
78
79 static int *f_integer(ExpHandle *eh, data1_node *c)
80 {
81     int *r;
82     char intbuf[64];
83
84     c = c->child;
85     if (!is_data_tag (eh, c) || c->u.data.len > 63)
86         return 0;
87     r = odr_malloc(eh->o, sizeof(*r));
88     sprintf(intbuf, "%.*s", 63, c->u.data.data);
89     *r = atoi(intbuf);
90     return r;
91 }
92
93 static char *f_string(ExpHandle *eh, data1_node *c)
94 {
95     char *r;
96
97     c = c->child;
98     if (!is_data_tag (eh, c))
99         return 0;
100     r = odr_malloc(eh->o, c->u.data.len+1);
101     memcpy(r, c->u.data.data, c->u.data.len);
102     r[c->u.data.len] = '\0';
103     return r;
104 }
105
106 static bool_t *f_bool(ExpHandle *eh, data1_node *c)
107 {
108     bool_t *tf;
109     char intbuf[64];
110
111     c = c->child;
112     if (!is_data_tag (eh, c) || c->u.data.len > 63)
113         return 0;
114     tf = odr_malloc (eh->o, sizeof(*tf));
115     sprintf(intbuf, "%.*s", c->u.data.len, c->u.data.data);
116     *tf = atoi(intbuf);
117     return tf;
118 }
119
120 static Odr_oid *f_oid(ExpHandle *eh, data1_node *c, oid_class oclass)
121 {
122     char oidstr[64];
123     int oid_this[20];
124     oid_value value_for_this;
125
126     c = c->child;
127     if (!is_data_tag (eh, c) || c->u.data.len > 63)
128         return 0;
129     sprintf(oidstr, "%.*s", c->u.data.len, c->u.data.data);
130     value_for_this = oid_getvalbyname(oidstr);
131     if (value_for_this == VAL_NONE)
132         return NULL; /* fix */
133     else
134     {
135         struct oident ident;
136
137         ident.oclass = oclass;
138         ident.proto = PROTO_Z3950;
139         ident.value = value_for_this;
140         
141         oid_ent_to_oid (&ident, oid_this);
142     }
143     return odr_oiddup (eh->o, oid_this);
144 }
145
146 static Z_IntUnit *f_intunit(ExpHandle *eh, data1_node *c)
147 {
148     /* fix */
149     return 0;
150 }
151
152 static Z_HumanString *f_humstring(ExpHandle *eh, data1_node *c)
153 {
154     Z_HumanString *r;
155     Z_HumanStringUnit *u;
156
157     c = c->child;
158     if (!is_data_tag (eh, c))
159         return 0;
160     r = odr_malloc(eh->o, sizeof(*r));
161     r->num_strings = 1;
162     r->strings = odr_malloc(eh->o, sizeof(Z_HumanStringUnit*));
163     r->strings[0] = u = odr_malloc(eh->o, sizeof(*u));
164     u->language = 0;
165     u->text = odr_malloc(eh->o, c->u.data.len+1);
166     memcpy(u->text, c->u.data.data, c->u.data.len);
167     u->text[c->u.data.len] = '\0';
168     return r;
169 }
170
171 static Z_CommonInfo *f_commonInfo(ExpHandle *eh, data1_node *n)
172 {
173     Z_CommonInfo *res = odr_malloc(eh->o, sizeof(*res));
174     data1_node *c;
175
176     res->dateAdded = 0;
177     res->dateChanged = 0;
178     res->expiry = 0;
179     res->humanStringLanguage = 0;
180     res->otherInfo = 0;
181
182     for (c = n->child; c; c = c->next)
183     {
184         switch (is_numeric_tag (eh, c))
185         {
186             case 601: res->dateAdded = f_string(eh, c); break;
187             case 602: res->dateChanged = f_string(eh, c); break;
188             case 603: res->expiry = f_string(eh, c); break;
189             case 604: res->humanStringLanguage = f_string(eh, c); break;
190         }
191     }
192     return res;
193 }
194
195 Z_QueryTypeDetails *f_queryTypeDetails (ExpHandle *eh, data1_node *n)
196 {
197     /* fix */
198     return NULL;
199 }
200
201 Odr_oid **f_oid_seq (ExpHandle *eh, data1_node *n, int *num, oid_class oclass)
202 {
203     Odr_oid **res;
204     data1_node *c;
205     int i;
206
207     *num = 0;
208     for (c = n->child ; c; c = c->next)
209     {
210         if (is_numeric_tag (eh, c) != 1000)
211             continue;
212         ++(*num);
213     }
214     if (!*num)
215         return NULL;
216     res = odr_malloc (eh->o, sizeof(*res) * (*num));
217     for (c = n->child, i = 0 ; c; c = c->next)
218     {
219         if (is_numeric_tag (eh, c) != 1000)
220             continue;
221         res[i++] = f_oid (eh, c, oclass);
222     }
223     return res;
224 }
225     
226 char **f_string_seq (ExpHandle *eh, data1_node *n, int *num)
227 {
228     char **res;
229     data1_node *c;
230     int i;
231
232     *num = 0;
233     for (c = n->child ; c; c = c->next)
234     {
235         if (!is_numeric_tag (eh, c) != 1001)
236             continue;
237         ++(*num);
238     }
239     if (!*num)
240         return NULL;
241     res = odr_malloc (eh->o, sizeof(*res) * (*num));
242     for (c = n->child, i = 0 ; c; c = c->next)
243     {
244         if (!is_numeric_tag (eh, c) != 1001)
245             continue;
246         res[i++] = f_string (eh, c);
247     }
248     return res;
249 }
250
251 char **f_humstring_seq (ExpHandle *eh, data1_node *n, int *num)
252 {
253     /* fix */
254     return NULL;
255 }
256
257
258 Z_RpnCapabilities *f_rpnCapabilities (ExpHandle *eh, data1_node *c)
259 {
260     Z_RpnCapabilities *res = odr_malloc (eh->o, sizeof(*res));
261
262     res->num_operators = 0;
263     res->operators = NULL;
264     res->resultSetAsOperandSupported = eh->false_value;
265     res->restrictionOperandSupported = eh->false_value;
266     res->proximity = NULL;
267     /* fix */ /* 550 - 560 */
268     return res;
269 }
270
271 Z_QueryTypeDetails **f_queryTypesSupported (ExpHandle *eh, data1_node *c,
272                                             int *num)
273 {
274     data1_node *n;
275     Z_QueryTypeDetails **res;
276     int i;
277
278     *num = 0;
279     for (n = c->child; n; n = n->next)
280     {
281         if (is_numeric_tag(eh, n) != 519)
282             continue;
283         /* fix */ /* 518 and 520 */
284         (*num)++;
285     }
286     if (!*num)
287         return NULL;
288     res = odr_malloc (eh->o, *num * sizeof(*res));
289     i = 0;
290     for (n = c->child; n; n = n->next)
291     {
292         if (is_numeric_tag(eh, n) == 519)
293         {
294             res[i] = odr_malloc (eh->o, sizeof(**res));
295             res[i]->which = Z_QueryTypeDetails_rpn;
296             res[i]->u.rpn = f_rpnCapabilities (eh, n);
297             i++;
298         }
299         else
300             continue;
301         /* fix */ /* 518 and 520 */
302     }
303     return res;
304 }
305
306 static Z_AccessInfo *f_accessInfo(ExpHandle *eh, data1_node *n)
307 {
308     Z_AccessInfo *res = odr_malloc(eh->o, sizeof(*res));
309     data1_node *c;
310
311     res->num_queryTypesSupported = 0;
312     res->queryTypesSupported = 0;
313     res->num_diagnosticsSets = 0;
314     res->diagnosticsSets = 0;
315     res->num_attributeSetIds = 0;
316     res->attributeSetIds = 0;
317     res->num_schemas = 0;
318     res->schemas = 0;
319     res->num_recordSyntaxes = 0;
320     res->recordSyntaxes = 0;
321     res->num_resourceChallenges = 0;
322     res->resourceChallenges = 0;
323     res->restrictedAccess = 0;
324     res->costInfo = 0;
325     res->num_variantSets = 0;
326     res->variantSets = 0;
327     res->num_elementSetNames = 0;
328     res->elementSetNames = 0;
329     res->num_unitSystems = 0;
330     res->unitSystems = 0;
331
332     for (c = n->child; c; c = c->next)
333     {
334         switch (is_numeric_tag (eh, c))
335         {
336         case 501:
337             res->queryTypesSupported =
338                 f_queryTypesSupported (eh, c, &res->num_queryTypesSupported);
339             break;
340         case 503:
341             res->diagnosticsSets =
342                 f_oid_seq(eh, c, &res->num_diagnosticsSets, CLASS_DIAGSET);
343             break;
344         case 505:
345             res->attributeSetIds =
346                 f_oid_seq(eh, c, &res->num_attributeSetIds, CLASS_ATTSET);
347             break;
348         case 507:
349             res->schemas =
350                 f_oid_seq(eh, c, &res->num_schemas, CLASS_SCHEMA);
351             break;
352         case 509:
353             res->recordSyntaxes =
354                 f_oid_seq (eh, c, &res->num_recordSyntaxes, CLASS_RECSYN);
355             break;
356         case 511:
357             res->resourceChallenges =
358                 f_oid_seq (eh, c, &res->num_resourceChallenges, CLASS_RESFORM);
359             break;
360         case 513: res->restrictedAccess = NULL; break; /* fix */
361         case 514: res->costInfo = NULL; break; /* fix */
362         case 515:
363             res->variantSets =
364                 f_oid_seq (eh, c, &res->num_variantSets, CLASS_VARSET);
365             break;
366         case 516:
367             res->elementSetNames =
368                 f_string_seq (eh, c, &res->num_elementSetNames);
369             break;
370         case 517:
371             res->unitSystems = f_string_seq (eh, c, &res->num_unitSystems);
372             break;
373         }
374     }
375     return res;
376 }
377
378 static int *f_recordCount(ExpHandle *eh, data1_node *c, int *which)
379 {
380     int *r= odr_malloc(eh->o, sizeof(*r));
381     int *wp = which;
382     char intbuf[64];
383
384     c = c->child;
385     if (!is_numeric_tag (eh, c))
386         return 0;
387     if (c->u.tag.element->tag->value.numeric == 210)
388         *wp = Z_Exp_RecordCount_actualNumber;
389     else if (c->u.tag.element->tag->value.numeric == 211)
390         *wp = Z_Exp_RecordCount_approxNumber;
391     else
392         return 0;
393     if (!c->child || c->child->which != DATA1N_data)
394         return 0;
395     sprintf(intbuf, "%.*s", 63, c->child->u.data.data);
396     *r = atoi(intbuf);
397     return r;
398 }
399
400 static Z_ContactInfo *f_contactInfo(ExpHandle *eh, data1_node *n)
401 {
402     /* fix */
403     return 0;
404 }
405
406 static Z_DatabaseList *f_databaseList(ExpHandle *eh, data1_node *n)
407 {
408     data1_node *c;
409     Z_DatabaseList *res;
410     int i = 0;
411     
412     for (c = n->child; c; c = c->next)
413     {
414         if (!is_numeric_tag (eh, c) != 102) 
415             continue;
416         ++i;
417     }
418     if (!i)
419         return NULL;
420
421     res = odr_malloc (eh->o, sizeof(*res));
422     
423     res->num_databases = i;
424     res->databases = odr_malloc (eh->o, sizeof(*res->databases) * i);
425     i = 0;
426     for (c = n->child; c; c = c->next)
427     {
428         if (!is_numeric_tag (eh, c) != 102)
429             continue;
430         res->databases[i++] = f_string (eh, c);
431     }
432     return res;
433 }
434
435 static Z_TargetInfo *f_targetInfo(ExpHandle *eh, data1_node *n)
436 {
437     Z_TargetInfo *res = odr_malloc(eh->o, sizeof(*res));
438     data1_node *c;
439
440     res->commonInfo = 0;
441     res->name = 0;
442     res->recentNews = 0;
443     res->icon = 0;
444     res->namedResultSets = 0;
445     res->multipleDbSearch = 0;
446     res->maxResultSets = 0;
447     res->maxResultSize = 0;
448     res->maxTerms = 0;
449     res->timeoutInterval = 0;
450     res->welcomeMessage = 0;
451     res->contactInfo = 0;
452     res->description = 0;
453     res->num_nicknames = 0;
454     res->nicknames = 0;
455     res->usageRest = 0;
456     res->paymentAddr = 0;
457     res->hours = 0;
458     res->num_dbCombinations = 0;
459     res->dbCombinations = 0;
460     res->num_addresses = 0;
461     res->addresses = 0;
462     res->commonAccessInfo = 0;
463     
464     for (c = n->child; c; c = c->next)
465     {
466         int i = 0;
467
468         if (!is_numeric_tag (eh, c))
469             continue;
470         switch (c->u.tag.element->tag->value.numeric)
471         {
472         case 600: res->commonInfo = f_commonInfo(eh, c); break;
473         case 102: res->name = f_string(eh, c); break;
474         case 103: res->recentNews = f_humstring(eh, c); break;
475         case 104: res->icon = NULL; break; /* fix */
476         case 105: res->namedResultSets = f_bool(eh, c); break;
477         case 106: res->multipleDbSearch = f_bool(eh, c); break;
478         case 107: res->maxResultSets = f_integer(eh, c); break;
479         case 108: res->maxResultSize = f_integer(eh, c); break;
480         case 109: res->maxTerms = f_integer(eh, c); break;
481         case 110: res->timeoutInterval = f_intunit(eh, c); break;
482         case 111: res->welcomeMessage = f_humstring(eh, c); break;
483         case 112: res->contactInfo = f_contactInfo(eh, c); break;
484         case 113: res->description = f_humstring(eh, c); break;
485         case 114: 
486             res->num_nicknames = 0;
487             for (n = c->child; n; n = n->next)
488             {
489                 if (is_numeric_tag(eh, n) != 102)
490                     continue;
491                 (res->num_nicknames)++;
492             }
493             if (res->num_nicknames)
494                 res->nicknames =
495                     odr_malloc (eh->o, res->num_nicknames 
496                                 * sizeof(*res->nicknames));
497             for (n = c->child; n; n = n->next)
498             {
499                 if (is_numeric_tag(eh, n) != 102)
500                     continue;
501                 res->nicknames[i++] = f_string (eh, n);
502             }
503             break;
504         case 115: res->usageRest = f_humstring(eh, c); break;
505         case 116: res->paymentAddr = f_humstring(eh, c); break;
506         case 117: res->hours = f_humstring(eh, c); break;
507         case 118:
508             res->num_dbCombinations = 0;
509             for (n = c->child; n; n = n->next)
510             {
511                 if (!is_numeric_tag(eh, n) != 605)
512                     continue;
513                 (res->num_dbCombinations)++;
514             }
515             if (res->num_dbCombinations)
516                 res->dbCombinations =
517                     odr_malloc (eh->o, res->num_dbCombinations
518                                 * sizeof(*res->dbCombinations));
519             for (n = c->child; n; n = n->next)
520             {
521                 if (!is_numeric_tag(eh, n) != 605)
522                     continue;
523                 res->dbCombinations[i++] = f_databaseList (eh, n);
524             }
525             break;
526         case 119: res->addresses = 0; break; /* fix */
527         case 500: res->commonAccessInfo = f_accessInfo(eh, c); break;
528         }
529     }
530     if (!res->namedResultSets)
531         res->namedResultSets = eh->false_value;
532     if (!res->multipleDbSearch)
533         res->multipleDbSearch = eh->false_value;
534     return res;
535 }
536
537 static Z_DatabaseInfo *f_databaseInfo(ExpHandle *eh, data1_node *n)
538 {
539     Z_DatabaseInfo *res = odr_malloc(eh->o, sizeof(*res));
540     data1_node *c;
541
542     res->commonInfo = 0;
543     res->name = 0;
544     res->explainDatabase = 0;
545     res->num_nicknames = 0;
546     res->nicknames = 0;
547     res->icon = 0;
548     res->userFee = 0;
549     res->available = 0;
550     res->titleString = 0;
551     res->num_keywords = 0;
552     res->keywords = 0;
553     res->description = 0;
554     res->associatedDbs = 0;
555     res->subDbs = 0;
556     res->disclaimers = 0;
557     res->news = 0;
558     res->recordCount = 0;
559     res->defaultOrder = 0;
560     res->avRecordSize = 0;
561     res->maxRecordSize = 0;
562     res->hours = 0;
563     res->bestTime = 0;
564     res->lastUpdate = 0;
565     res->updateInterval = 0;
566     res->coverage = 0;
567     res->proprietary = 0;
568     res->copyrightText = 0;
569     res->copyrightNotice = 0;
570     res->producerContactInfo = 0;
571     res->supplierContactInfo = 0;
572     res->submissionContactInfo = 0;
573     res->accessInfo = 0;
574     
575     for (c = n->child; c; c = c->next)
576     {
577         int i = 0;
578
579         switch (is_numeric_tag (eh, c))
580         {
581         case 600: res->commonInfo = f_commonInfo(eh, c); break;
582         case 102: res->name = f_string(eh, c); break;
583         case 226: res->explainDatabase = odr_nullval(); break;
584         case 114:
585             res->num_nicknames = 0;
586             for (n = c->child; n; n = n->next)
587             {
588                 if (!is_numeric_tag(eh, n) ||
589                     n->u.tag.element->tag->value.numeric != 102)
590                     continue;
591                 (res->num_nicknames)++;
592             }
593             if (res->num_nicknames)
594                 res->nicknames =
595                     odr_malloc (eh->o, res->num_nicknames 
596                                 * sizeof(*res->nicknames));
597             for (n = c->child; n; n = n->next)
598             {
599                 if (!is_numeric_tag(eh, n) ||
600                     n->u.tag.element->tag->value.numeric != 102)
601                     continue;
602                 res->nicknames[i++] = f_string (eh, n);
603             }
604             break;
605         case 104: res->icon = 0; break;      /* fix */
606         case 201: res->userFee = f_bool(eh, c); break;
607         case 202: res->available = f_bool(eh, c); break;
608         case 203: res->titleString = f_humstring(eh, c); break;
609         case 227:
610             res->num_keywords = 0;
611             for (n = c->child; n; n = n->next)
612             {
613                 if (!is_numeric_tag(eh, n) != 1000)
614                     continue;
615                 (res->num_keywords)++;
616             }
617             if (res->num_keywords)
618                 res->keywords =
619                     odr_malloc (eh->o, res->num_keywords 
620                                 * sizeof(*res->keywords));
621             for (n = c->child; n; n = n->next)
622             {
623                 if (!is_numeric_tag(eh, n) != 1000)
624                     continue;
625                 res->keywords[i++] = f_humstring (eh, n);
626             }
627             break;
628         case 113: res->description = f_humstring(eh, c); break;
629         case 205:
630             res->associatedDbs = f_databaseList (eh, c);
631             break;
632         case 206:
633             res->subDbs = f_databaseList (eh, c);
634             break;
635         case 207: res->disclaimers = f_humstring(eh, c); break;
636         case 103: res->news = f_humstring(eh, c); break;
637         case 209: res->recordCount =
638                       f_recordCount(eh, c, &res->recordCount_which); break;
639         case 212: res->defaultOrder = f_humstring(eh, c); break;
640         case 213: res->avRecordSize = f_integer(eh, c); break;
641         case 214: res->maxRecordSize = f_integer(eh, c); break;
642         case 215: res->hours = f_humstring(eh, c); break;
643         case 216: res->bestTime = f_humstring(eh, c); break;
644         case 217: res->lastUpdate = f_string(eh, c); break;
645         case 218: res->updateInterval = f_intunit(eh, c); break;
646         case 219: res->coverage = f_humstring(eh, c); break;
647         case 220: res->proprietary = f_bool(eh, c); break;
648         case 221: res->copyrightText = f_humstring(eh, c); break;
649         case 222: res->copyrightNotice = f_humstring(eh, c); break;
650         case 223: res->producerContactInfo = f_contactInfo(eh, c); break;
651         case 224: res->supplierContactInfo = f_contactInfo(eh, c); break;
652         case 225: res->submissionContactInfo = f_contactInfo(eh, c); break;
653         case 500: res->accessInfo = f_accessInfo(eh, c); break;
654         }
655     }
656     if (!res->userFee)
657         res->userFee = eh->false_value;
658     if (!res->available)
659         res->available = eh->true_value;
660     return res;
661 }
662
663 Z_ExplainRecord *data1_nodetoexplain (data1_handle dh, data1_node *n,
664                                       int select, ODR o)
665 {
666     ExpHandle eh;
667     Z_ExplainRecord *res = odr_malloc(o, sizeof(*res));
668
669     eh.dh = dh;
670     eh.select = select;
671     eh.o = o;
672     eh.false_value = odr_malloc(eh.o, sizeof(eh.false_value));
673     *eh.false_value = 0;
674     eh.true_value = odr_malloc(eh.o, sizeof(eh.true_value));
675     *eh.true_value = 1;
676
677     assert(n->which == DATA1N_root);
678     if (strcmp(n->u.root.type, "explain"))
679     {
680         logf(LOG_WARN, "Attempt to convert a non-Explain record");
681         return 0;
682     }
683     n = n->child;
684     if (!n || n->next)
685     {
686         logf(LOG_WARN, "Explain record should have one exactly one child");
687         return 0;
688     }
689     switch (is_numeric_tag (&eh, n))
690     {
691     case 1:
692         res->which = Z_Explain_targetInfo;
693         if (!(res->u.targetInfo = f_targetInfo(&eh, n)))
694             return 0;
695         break;
696     case 2:
697         res->which = Z_Explain_databaseInfo;
698         if (!(res->u.databaseInfo = f_databaseInfo(&eh, n)))
699             return 0;
700         break;
701     default:
702         logf(LOG_WARN, "Unknown explain category");
703         return 0;
704     }
705     return res;
706 }