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