More explain work.
[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.5  1997-11-19 10:30:06  adam
8  * More explain work.
9  *
10  * Revision 1.4  1997/11/18 09:51:08  adam
11  * Removed element num_children from data1_node. Minor changes in
12  * data1 to Explain.
13  *
14  * Revision 1.3  1997/09/17 12:10:36  adam
15  * YAZ version 1.4.
16  *
17  * Revision 1.2  1995/12/14 16:28:30  quinn
18  * More explain stuff.
19  *
20  * Revision 1.1  1995/12/14  11:09:51  quinn
21  * Work on Explain
22  *
23  *
24  */
25
26 #include <assert.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include <log.h>
31 #include <proto.h>
32 #include <data1.h>
33
34 typedef struct {
35     data1_handle dh;
36     ODR o;
37     int select;
38 } ExpHandle;
39
40 static int is_numeric_tag (ExpHandle *eh, data1_node *c)
41 {
42     if (!c || c->which != DATA1N_tag)
43         return 0;
44     if (!c->u.tag.element)
45     {
46         logf(LOG_WARN, "Tag %s is local", c->u.tag.tag);
47         return 0;
48     }
49     if (c->u.tag.element->tag->which != DATA1T_numeric)
50     {
51         logf(LOG_WARN, "Tag %s is not numeric", c->u.tag.tag);
52         return 0;
53     }
54     if (eh->select && !c->u.tag.node_selected)
55         return 0;
56     return 1;
57 }
58
59 static int is_data_tag (ExpHandle *eh, data1_node *c)
60 {
61     if (!c || c->which != DATA1N_data)
62         return 0;
63     if (select && !c->u.tag.node_selected)
64         return 0;
65     return 1;
66 }
67
68 static int *f_integer(ExpHandle *eh, data1_node *c)
69 {
70     int *r;
71     char intbuf[64];
72
73     c = c->child;
74     if (!is_data_tag (eh, c) || c->u.data.len > 63)
75         return 0;
76     r = odr_malloc(eh->o, sizeof(*r));
77     sprintf(intbuf, "%.*s", 63, c->u.data.data);
78     *r = atoi(intbuf);
79     return r;
80 }
81
82 static char *f_string(ExpHandle *eh, data1_node *c)
83 {
84     char *r;
85
86     c = c->child;
87     if (!is_data_tag (eh, c))
88         return 0;
89     r = odr_malloc(eh->o, c->u.data.len+1);
90     memcpy(r, c->u.data.data, c->u.data.len);
91     r[c->u.data.len] = '\0';
92     return r;
93 }
94
95 static bool_t *f_bool(ExpHandle *eh, data1_node *c)
96 {
97     bool_t *tf;
98     char intbuf[64];
99
100     c = c->child;
101     if (!is_data_tag (eh, c) || c->u.data.len > 63)
102         return 0;
103     tf = odr_malloc (eh->o, sizeof(*tf));
104     sprintf(intbuf, "%.*s", 63, c->u.data.data);
105     *tf = atoi(intbuf);
106     return tf;
107 }
108
109 static Z_IntUnit *f_intunit(ExpHandle *eh, data1_node *c)
110 {
111     return 0;
112 }
113
114 static Z_HumanString *f_humstring(ExpHandle *eh, data1_node *c)
115 {
116     Z_HumanString *r;
117     Z_HumanStringUnit *u;
118
119     c = c->child;
120     if (!is_data_tag (eh, c))
121         return 0;
122     r = odr_malloc(eh->o, sizeof(*r));
123     r->num_strings = 1;
124     r->strings = odr_malloc(eh->o, sizeof(Z_HumanStringUnit*));
125     r->strings[0] = u = odr_malloc(eh->o, sizeof(*u));
126     u->language = 0;
127     u->text = odr_malloc(eh->o, c->u.data.len+1);
128     memcpy(u->text, c->u.data.data, c->u.data.len);
129     u->text[c->u.data.len] = '\0';
130     return r;
131 }
132
133 static Z_CommonInfo *f_commonInfo(ExpHandle *eh, data1_node *n)
134 {
135     Z_CommonInfo *res = odr_malloc(eh->o, sizeof(*res));
136     data1_node *c;
137
138     res->dateAdded = 0;
139     res->dateChanged = 0;
140     res->expiry = 0;
141     res->humanStringLanguage = 0;
142     res->otherInfo = 0;
143
144     for (c = n->child; c; c = c->next)
145     {
146         if (!is_numeric_tag (eh, c))
147             continue;
148         switch (c->u.tag.element->tag->value.numeric)
149         {
150             case 601: res->dateAdded = f_string(eh, c); break;
151             case 602: res->dateChanged = f_string(eh, c); break;
152             case 603: res->expiry = f_string(eh, c); break;
153             case 604: res->humanStringLanguage = f_string(eh, c); break;
154             /* otherInfo? */
155             default:
156                 logf(LOG_WARN, "Bad child in commonInfo");
157                 return 0;
158         }
159     }
160     return res;
161 }
162
163 static Z_AccessInfo *f_accessInfo(ExpHandle *eh, data1_node *n)
164 {
165     Z_AccessInfo *res = odr_malloc(eh->o, sizeof(*res));
166     data1_node *c;
167
168     res->num_queryTypesSupported = 0;
169     res->queryTypesSupported = 0;
170     res->num_diagnosticsSets = 0;
171     res->diagnosticsSets = 0;
172     res->num_attributeSetIds = 0;
173     res->attributeSetIds = 0;
174     res->num_schemas = 0;
175     res->schemas = 0;
176     res->num_recordSyntaxes = 0;
177     res->recordSyntaxes = 0;
178     res->num_resourceChallenges = 0;
179     res->resourceChallenges = 0;
180     res->restrictedAccess = 0;
181     res->costInfo = 0;
182     res->num_variantSets = 0;
183     res->variantSets = 0;
184     res->num_elementSetNames = 0;
185     res->elementSetNames = 0;
186     res->num_unitSystems = 0;
187     res->unitSystems = 0;
188
189     for (c = n->child; c; c = c->next)
190     {
191         if (c->which != DATA1N_tag || !c->u.tag.element)
192         {
193             logf(LOG_WARN, "Malformed explain record");
194             return 0;
195         }
196         if (eh->select && !c->u.tag.node_selected)
197             continue;
198         /* switch-statement here */
199     }
200     return res;
201 }
202
203 static int *f_recordCount(ExpHandle *eh, data1_node *c, int *which)
204 {
205     int *r= odr_malloc(eh->o, sizeof(*r));
206     int *wp = which;
207     char intbuf[64];
208
209     c = c->child;
210     if (!is_numeric_tag (eh, c))
211         return 0;
212     if (c->u.tag.element->tag->value.numeric == 210)
213         *wp = Z_Exp_RecordCount_actualNumber;
214     else if (c->u.tag.element->tag->value.numeric == 211)
215         *wp = Z_Exp_RecordCount_approxNumber;
216     else
217         return 0;
218     if (!c->child || c->child->which != DATA1N_data)
219         return 0;
220     sprintf(intbuf, "%.*s", 63, c->child->u.data.data);
221     *r = atoi(intbuf);
222     return r;
223 }
224
225 static Z_ContactInfo *f_contactInfo(ExpHandle *eh, data1_node *n)
226 {
227     return 0;
228 }
229
230 static Z_TargetInfo *f_targetInfo(ExpHandle *eh, data1_node *n)
231 {
232     Z_TargetInfo *res = odr_malloc(eh->o, sizeof(*res));
233     data1_node *c;
234     bool_t *fl = odr_malloc(eh->o,sizeof(*fl));
235
236     *fl = 0;
237     res->commonInfo = 0;
238     res->name = 0;
239     res->recentNews = 0;
240     res->icon = 0;
241     res->namedResultSets = 0;
242     res->multipleDbSearch = 0;
243     res->maxResultSets = 0;
244     res->maxResultSize = 0;
245     res->maxTerms = 0;
246     res->timeoutInterval = 0;
247     res->welcomeMessage = 0;
248     res->contactInfo = 0;
249     res->description = 0;
250     res->num_nicknames = 0;
251     res->nicknames = 0;
252     res->usageRest = 0;
253     res->paymentAddr = 0;
254     res->hours = 0;
255     res->num_dbCombinations = 0;
256     res->dbCombinations = 0;
257     res->num_addresses = 0;
258     res->addresses = 0;
259     res->commonAccessInfo = 0;
260
261     for (c = n->child; c; c = c->next)
262     {
263         if (!is_numeric_tag (eh, c))
264             continue;
265         switch (c->u.tag.element->tag->value.numeric)
266         {
267             case 600: res->commonInfo = f_commonInfo(eh, c); break;
268             case 102: res->name = f_string(eh, c); break;
269             case 103: res->recentNews = f_humstring(eh, c); break;
270             case 104: break; /* icon */
271             case 105: res->namedResultSets = f_bool(eh, c); break;
272             case 106: res->multipleDbSearch = f_bool(eh, c); break;
273             case 107: res->maxResultSets = f_integer(eh, c); break;
274             case 108: res->maxResultSize = f_integer(eh, c); break;
275             case 109: res->maxTerms = f_integer(eh, c); break;
276             case 110: res->timeoutInterval = f_intunit(eh, c); break;
277             case 111: res->welcomeMessage = f_humstring(eh, c); break;
278             case 112: res->contactInfo = f_contactInfo(eh, c); break;
279             case 113: res->description = f_humstring(eh, c); break;
280             case 114: break; /* nicknames */
281             case 115: res->usageRest = f_humstring(eh, c); break;
282             case 116: res->paymentAddr = f_humstring(eh, c); break;
283             case 117: res->hours = f_humstring(eh, c); break;
284             case 118: break; /* dbcombinations */
285             case 119: break; /* addresses */
286             case 500: res->commonAccessInfo = f_accessInfo(eh, c); break;
287             default:
288                 logf(LOG_WARN, "Unknown target-info element");
289         }
290     }
291     if (!res->namedResultSets)
292         res->namedResultSets = fl;
293     if (!res->multipleDbSearch)
294         res->multipleDbSearch = fl;
295     return res;
296 }
297
298 static Z_DatabaseInfo *f_databaseInfo(ExpHandle *eh, data1_node *n)
299 {
300     Z_DatabaseInfo *res = odr_malloc(eh->o, sizeof(*res));
301     data1_node *c;
302     bool_t *fl = odr_malloc(eh->o,sizeof(*fl));
303     bool_t *tr = odr_malloc(eh->o,sizeof(*tr));
304
305     *fl = 0;
306     *tr = 1;
307     res->commonInfo = 0;
308     res->name = 0;
309     res->explainDatabase = 0;
310     res->num_nicknames = 0;
311     res->nicknames = 0;
312     res->icon = 0;
313     res->userFee = 0;
314     res->available = 0;
315     res->titleString = 0;
316     res->num_keywords = 0;
317     res->keywords = 0;
318     res->description = 0;
319     res->associatedDbs = 0;
320     res->subDbs = 0;
321     res->disclaimers = 0;
322     res->news = 0;
323     res->recordCount = 0;
324     res->defaultOrder = 0;
325     res->avRecordSize = 0;
326     res->maxRecordSize = 0;
327     res->hours = 0;
328     res->bestTime = 0;
329     res->lastUpdate = 0;
330     res->updateInterval = 0;
331     res->coverage = 0;
332     res->proprietary = 0;
333     res->copyrightText = 0;
334     res->copyrightNotice = 0;
335     res->producerContactInfo = 0;
336     res->supplierContactInfo = 0;
337     res->submissionContactInfo = 0;
338     res->accessInfo = 0;
339     
340     for (c = n->child; c; c = c->next)
341     {
342         if (!is_numeric_tag (eh, c))
343             continue;
344         switch (c->u.tag.element->tag->value.numeric)
345         {
346         case 600: res->commonInfo = f_commonInfo(eh, c); break;
347         case 102: res->name = f_string(eh, c); break;
348         case 226: res->explainDatabase = ODR_NULLVAL; break;
349         case 114: res->num_nicknames = 0; res->nicknames = 0; break; /* fix */
350         case 104: res->icon = 0; break;      /* fix */
351         case 201: res->userFee = f_bool(eh, c); break;
352         case 202: res->available = f_bool(eh, c); break;
353         case 203: res->titleString = f_humstring(eh, c); break;
354         case 227: res->num_keywords = 0; res->keywords = 0; break; /* fix */
355         case 113: res->description = f_humstring(eh, c); break;
356         case 205: res->associatedDbs = 0; break; /* fix */
357         case 206: res->subDbs = 0; break; /* fix */
358         case 207: res->disclaimers = f_humstring(eh, c); break;
359         case 103: res->news = f_humstring(eh, c); break;
360         case 209: res->recordCount =
361                       f_recordCount(eh, c, &res->recordCount_which); break;
362         case 212: res->defaultOrder = f_humstring(eh, c); break;
363         case 213: res->avRecordSize = f_integer(eh, c); break;
364         case 214: res->maxRecordSize = f_integer(eh, c); break;
365         case 215: res->hours = f_humstring(eh, c); break;
366         case 216: res->bestTime = f_humstring(eh, c); break;
367         case 217: res->lastUpdate = f_string(eh, c); break;
368         case 218: res->updateInterval = f_intunit(eh, c); break;
369         case 219: res->coverage = f_humstring(eh, c); break;
370         case 220: res->proprietary = f_bool(eh, c); break;
371         case 221: res->copyrightText = f_humstring(eh, c); break;
372         case 222: res->copyrightNotice = f_humstring(eh, c); break;
373         case 223: res->producerContactInfo = f_contactInfo(eh, c); break;
374         case 224: res->supplierContactInfo = f_contactInfo(eh, c); break;
375         case 225: res->submissionContactInfo = f_contactInfo(eh, c); break;
376         case 500: res->accessInfo = f_accessInfo(eh, c); break;
377         default:
378             logf(LOG_WARN, "Unknown element in databaseInfo");
379         }
380     }
381     if (!res->userFee)
382         res->userFee = fl;
383     if (!res->available)
384         res->available = tr;
385     return res;
386 }
387
388 Z_ExplainRecord *data1_nodetoexplain (data1_handle dh, data1_node *n,
389                                       int select, ODR o)
390 {
391     ExpHandle eh;
392     Z_ExplainRecord *res = odr_malloc(o, sizeof(*res));
393
394     eh.dh = dh;
395     eh.select = select;
396     eh.o = o;
397
398     assert(n->which == DATA1N_root);
399     if (strcmp(n->u.root.type, "explain"))
400     {
401         logf(LOG_WARN, "Attempt to convert a non-Explain record");
402         return 0;
403     }
404     n = n->child;
405     if (!n || n->next)
406     {
407         logf(LOG_WARN, "Explain record should have one exactly one child");
408         return 0;
409     }
410     if (!is_numeric_tag (&eh, n))
411         return 0;
412     switch (n->u.tag.element->tag->value.numeric)
413     {
414     case 0:
415         res->which = Z_Explain_targetInfo;
416         if (!(res->u.targetInfo = f_targetInfo(&eh, n)))
417             return 0;
418         break;
419     case 1:
420         res->which = Z_Explain_databaseInfo;
421         if (!(res->u.databaseInfo = f_databaseInfo(&eh, n)))
422             return 0;
423         break;
424     default:
425         logf(LOG_WARN, "Unknown explain category");
426         return 0;
427     }
428     return res;
429 }