df7c04e754f0e98f765b50228940d8dc8c709ed2
[yaz-moved-to-github.git] / src / srw.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srw.c,v 1.5 2003-12-22 14:24:10 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9
10 #if HAVE_XML2
11 #include <libxml/parser.h>
12 #include <libxml/tree.h>
13
14 static void add_XML_n(xmlNodePtr ptr, const char *elem, char *val, int len)
15 {
16     if (val)
17     {
18         xmlDocPtr doc = xmlParseMemory(val,len);
19         if (doc)
20         {
21             xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
22             xmlNodePtr t = xmlDocGetRootElement(doc);
23             xmlAddChild(c, xmlCopyNode(t,1));
24             xmlFreeDoc(doc);
25         }
26     }
27 }
28
29 xmlNodePtr add_xsd_string_n(xmlNodePtr ptr, const char *elem, char *val,
30                             int len)
31 {
32     if (val)
33     {
34         xmlNodePtr c = xmlNewChild(ptr, 0, elem, 0);
35         xmlNodePtr t = xmlNewTextLen(val, len);
36         xmlAddChild(c, t);
37         return t;
38     }
39     return 0;
40 }
41
42 xmlNodePtr add_xsd_string(xmlNodePtr ptr, const char *elem, char *val)
43 {
44     if (val)
45         return xmlNewChild(ptr, 0, elem, val);
46     return 0;
47 }
48
49 static void add_xsd_integer(xmlNodePtr ptr, const char *elem, int *val)
50 {
51     if (val)
52     {
53         char str[30];
54         sprintf(str, "%d", *val);
55         xmlNewChild(ptr, 0, elem, str);
56     }
57 }
58
59 static int match_element(xmlNodePtr ptr, const char *elem)
60 {
61     if (ptr->type == XML_ELEMENT_NODE && !strcmp(ptr->name, elem))
62         return 1;
63     return 0;
64 }
65
66 #define CHECK_TYPE 0
67
68 static int match_xsd_string_n(xmlNodePtr ptr, const char *elem, ODR o,
69                               char **val, int *len)
70 {
71 #if CHECK_TYPE
72     struct _xmlAttr *attr;
73 #endif
74     if (!match_element(ptr, elem))
75         return 0;
76 #if CHECK_TYPE
77     for (attr = ptr->properties; attr; attr = attr->next)
78         if (!strcmp(attr->name, "type") &&
79             attr->children && attr->children->type == XML_TEXT_NODE)
80         {
81             const char *t = strchr(attr->children->content, ':');
82             if (t)
83                 t = t + 1;
84             else
85                 t = attr->children->content;
86             if (!strcmp(t, "string"))
87                 break;
88         }
89     if (!attr)
90         return 0;
91 #endif
92     ptr = ptr->children;
93     if (!ptr || ptr->type != XML_TEXT_NODE)
94         return 0;
95     *val = odr_strdup(o, ptr->content);
96     if (len)
97         *len = strlen(ptr->content);
98     return 1;
99 }
100
101
102 static int match_xsd_string(xmlNodePtr ptr, const char *elem, ODR o,
103                             char **val)
104 {
105     return match_xsd_string_n(ptr, elem, o, val, 0);
106 }
107
108 static int match_xsd_XML_n(xmlNodePtr ptr, const char *elem, ODR o,
109                            char **val, int *len)
110 {
111     xmlBufferPtr buf;
112
113     if (!match_element(ptr, elem))
114         return 0;
115     ptr = ptr->children;
116     if (!ptr)
117         return 0;
118     buf = xmlBufferCreate();
119
120     xmlNodeDump(buf, ptr->doc, ptr, 0, 0);
121
122     *val = odr_malloc(o, buf->use+1);
123     memcpy (*val, buf->content, buf->use);
124     (*val)[buf->use] = '\0';
125
126     if (len)
127         *len = buf->use;
128
129     xmlBufferFree(buf);
130
131     return 1;
132 }
133
134                      
135 static int match_xsd_integer(xmlNodePtr ptr, const char *elem, ODR o, int **val)
136 {
137 #if CHECK_TYPE
138     struct _xmlAttr *attr;
139 #endif
140     if (!match_element(ptr, elem))
141         return 0;
142 #if CHECK_TYPE
143     for (attr = ptr->properties; attr; attr = attr->next)
144         if (!strcmp(attr->name, "type") &&
145             attr->children && attr->children->type == XML_TEXT_NODE)
146         {
147             const char *t = strchr(attr->children->content, ':');
148             if (t)
149                 t = t + 1;
150             else
151                 t = attr->children->content;
152             if (!strcmp(t, "integer"))
153                 break;
154         }
155     if (!attr)
156         return 0;
157 #endif
158     ptr = ptr->children;
159     if (!ptr || ptr->type != XML_TEXT_NODE)
160         return 0;
161     *val = odr_intdup(o, atoi(ptr->content));
162     return 1;
163 }
164
165 static int yaz_srw_record(ODR o, xmlNodePtr pptr, Z_SRW_record *rec,
166                           void *client_data, const char *ns)
167 {
168     if (o->direction == ODR_DECODE)
169     {
170         int pack = Z_SRW_recordPacking_string;
171         xmlNodePtr ptr;
172         rec->recordSchema = 0;
173         rec->recordData_buf = 0;
174         rec->recordData_len = 0;
175         rec->recordPosition = 0;
176         for (ptr = pptr->children; ptr; ptr = ptr->next)
177         {
178             char *spack = 0;
179             
180             if (match_xsd_string(ptr, "recordSchema", o, 
181                                  &rec->recordSchema))
182                 ;
183             else if (match_xsd_string(ptr, "recordPacking", o, &spack))
184             {
185                 if (pack && !strcmp(spack, "xml"))
186                     pack = Z_SRW_recordPacking_XML;
187                 if (pack && !strcmp(spack, "string"))
188                     pack = Z_SRW_recordPacking_string;
189             }
190             else if (match_xsd_integer(ptr, "recordPosition", o, 
191                                        &rec->recordPosition))
192                 ;
193             else 
194             {
195                 if (pack == Z_SRW_recordPacking_XML)
196                     match_xsd_XML_n(ptr, "recordData", o, 
197                                     &rec->recordData_buf,
198                                     &rec->recordData_len);
199                 if (pack == Z_SRW_recordPacking_string)
200                     match_xsd_string_n(ptr, "recordData", o, 
201                                        &rec->recordData_buf,
202                                        &rec->recordData_len);
203             }
204         }
205         rec->recordPacking = pack;
206     }
207     else if (o->direction == ODR_ENCODE)
208     {
209         xmlNodePtr ptr = pptr;
210         add_xsd_string(ptr, "recordSchema", rec->recordSchema);
211         switch(rec->recordPacking)
212         {
213         case Z_SRW_recordPacking_string:
214             add_xsd_string(ptr, "recordPacking", "string");
215             add_xsd_string_n(ptr, "recordData", rec->recordData_buf,
216                              rec->recordData_len);
217             break;
218         case Z_SRW_recordPacking_XML:
219             add_xsd_string(ptr, "recordPacking", "xml");
220             add_XML_n(ptr, "recordData", rec->recordData_buf,
221                       rec->recordData_len);
222             break;
223         }
224         add_xsd_integer(ptr, "recordPosition", rec->recordPosition);
225     }
226 }
227
228 static int yaz_srw_records(ODR o, xmlNodePtr pptr, Z_SRW_record **recs,
229                            int *num, void *client_data, const char *ns)
230 {
231     if (o->direction == ODR_DECODE)
232     {
233         int i;
234         xmlNodePtr ptr;
235         *num = 0;
236         for (ptr = pptr->children; ptr; ptr = ptr->next)
237         {
238             if (ptr->type == XML_ELEMENT_NODE &&
239                 !strcmp(ptr->name, "record"))
240                 (*num)++;
241         }
242         if (!*num)
243             return 1;
244         *recs = odr_malloc(o, *num * sizeof(**recs));
245         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
246         {
247             if (ptr->type == XML_ELEMENT_NODE &&
248                 !strcmp(ptr->name, "record"))
249                 yaz_srw_record(o, ptr, (*recs)+i, client_data, ns);
250         }
251     }
252     else if (o->direction == ODR_ENCODE)
253     {
254         int i;
255         for (i = 0; i < *num; i++)
256         {
257             xmlNodePtr rptr = xmlNewChild(pptr, 0, "record", 0);
258             yaz_srw_record(o, rptr, (*recs)+i, client_data, ns);
259         }
260     }
261     return 0;
262 }
263
264 static int yaz_srw_diagnostics(ODR o, xmlNodePtr pptr, Z_SRW_diagnostic **recs,
265                                int *num, void *client_data, const char *ns)
266 {
267     if (o->direction == ODR_DECODE)
268     {
269         int i;
270         xmlNodePtr ptr;
271         *num = 0;
272         for (ptr = pptr->children; ptr; ptr = ptr->next)
273         {
274             if (ptr->type == XML_ELEMENT_NODE &&
275                 !strcmp(ptr->name, "diagnostic"))
276                 (*num)++;
277         }
278         if (!*num)
279             return 1;
280         *recs = odr_malloc(o, *num * sizeof(**recs));
281         for (i = 0, ptr = pptr->children; ptr; ptr = ptr->next, i++)
282         {
283             if (ptr->type == XML_ELEMENT_NODE &&
284                 !strcmp(ptr->name, "diagnostic"))
285             {
286                 xmlNodePtr rptr;
287                 (*recs)[i].code = 0;
288                 (*recs)[i].details = 0;
289                 for (rptr = ptr->children; rptr; rptr = rptr->next)
290                 {
291                     if (match_xsd_integer(rptr, "code", o, 
292                                                &(*recs)[i].code))
293                         ;
294                     else if (match_xsd_string(rptr, "details", o, 
295                                               &(*recs)[i].details))
296                         ;
297                 }
298                 i++;
299             }
300         }
301     }
302     else if (o->direction == ODR_ENCODE)
303     {
304         int i;
305         for (i = 0; i < *num; i++)
306         {
307             xmlNodePtr rptr = xmlNewChild(pptr, 0, "diagnostic", 0);
308             add_xsd_integer(rptr, "code", (*recs)[i].code);
309             add_xsd_string(rptr, "details", (*recs)[i].details);
310         }
311     }
312     return 0;
313 }
314
315
316 int yaz_srw_codec(ODR o, void * vptr, Z_SRW_PDU **handler_data,
317                   void *client_data, const char *ns)
318 {
319     xmlNodePtr pptr = vptr;
320     if (o->direction == ODR_DECODE)
321     {
322         Z_SRW_PDU **p = handler_data;
323         xmlNodePtr method = pptr->children;
324
325         while (method && method->type == XML_TEXT_NODE)
326             method = method->next;
327         
328         if (!method)
329             return -1;
330         if (method->type != XML_ELEMENT_NODE)
331             return -1;
332
333         *p = odr_malloc(o, sizeof(**p));
334         (*p)->srw_version = odr_strdup(o, "1.1");
335         
336         if (!strcmp(method->name, "searchRetrieveRequest"))
337         {
338             xmlNodePtr ptr = method->children;
339             Z_SRW_searchRetrieveRequest *req;
340
341             (*p)->which = Z_SRW_searchRetrieve_request;
342             req = (*p)->u.request = odr_malloc(o, sizeof(*req));
343             req->query_type = Z_SRW_query_type_cql;
344             req->query.cql = 0;
345             req->sort_type = Z_SRW_sort_type_none;
346             req->sort.none = 0;
347             req->startRecord = 0;
348             req->maximumRecords = 0;
349             req->recordSchema = 0;
350             req->recordPacking = 0;
351             req->database = 0;
352
353             for (; ptr; ptr = ptr->next)
354             {
355                 if (match_xsd_string(ptr, "query", o, 
356                                      &req->query.cql))
357                     req->query_type = Z_SRW_query_type_cql;
358                 else if (match_xsd_string(ptr, "pQuery", o, 
359                                      &req->query.pqf))
360                     req->query_type = Z_SRW_query_type_pqf;
361                 else if (match_xsd_string(ptr, "xQuery", o, 
362                                      &req->query.xcql))
363                     req->query_type = Z_SRW_query_type_xcql;
364                 else if (match_xsd_string(ptr, "sortKeys", o, 
365                                           &req->sort.sortKeys))
366                     req->sort_type = Z_SRW_sort_type_sort;
367                 else if (match_xsd_string(ptr, "recordSchema", o, 
368                                           &req->recordSchema))
369                     ;
370                 else if (match_xsd_string(ptr, "recordPacking", o,
371                                           &req->recordPacking))
372                     ;
373                 else if (match_xsd_integer(ptr, "startRecord", o,
374                                            &req->startRecord))
375                     ;
376                 else if (match_xsd_integer(ptr, "maximumRecords", o,
377                                            &req->maximumRecords))
378                     ;
379                 else if (match_xsd_string(ptr, "database", o,
380                                            &req->database))
381                     ;
382                 else if (match_xsd_string(ptr, "version", o,
383                                            &(*p)->srw_version))
384                     ;
385                 /* missing is xQuery, xSortKeys .. */
386             }
387         }
388         else if (!strcmp(method->name, "searchRetrieveResponse"))
389         {
390             xmlNodePtr ptr = method->children;
391             Z_SRW_searchRetrieveResponse *res;
392
393             (*p)->which = Z_SRW_searchRetrieve_response;
394             res = (*p)->u.response = odr_malloc(o, sizeof(*res));
395
396             res->numberOfRecords = 0;
397             res->resultSetId = 0;
398             res->resultSetIdleTime = 0;
399             res->records = 0;
400             res->num_records = 0;
401             res->diagnostics = 0;
402             res->num_diagnostics = 0;
403             res->nextRecordPosition = 0;
404
405             for (; ptr; ptr = ptr->next)
406             {
407                 if (match_xsd_integer(ptr, "numberOfRecords", o, 
408                                       &res->numberOfRecords))
409                     ;
410                 else if (match_xsd_string(ptr, "resultSetId", o, 
411                                           &res->resultSetId))
412                     ;
413                 else if (match_xsd_integer(ptr, "resultSetIdleTime", o, 
414                                            &res->resultSetIdleTime))
415                     ;
416                 else if (match_element(ptr, "records"))
417                     yaz_srw_records(o, ptr, &res->records,
418                                     &res->num_records, client_data,
419                                     ns);
420                 else if (match_element(ptr, "diagnostics"))
421                     yaz_srw_diagnostics(o, ptr, &res->diagnostics,
422                                         &res->num_diagnostics,
423                                         client_data, ns);
424                 else if (match_xsd_integer(ptr, "nextRecordPosition", o,
425                                            &res->nextRecordPosition))
426                     ;
427                 else if (match_xsd_string(ptr, "version", o,
428                                            &(*p)->srw_version))
429                     ;
430             }
431         }
432         else if (!strcmp(method->name, "explainRequest"))
433         {
434             Z_SRW_explainRequest *req;
435             xmlNodePtr ptr = method->children;
436             
437             (*p)->which = Z_SRW_explain_request;
438             req = (*p)->u.explain_request = odr_malloc(o, sizeof(*req));
439             req->recordPacking = 0;
440             req->database = 0;
441             for (; ptr; ptr = ptr->next)
442             {
443                 if (match_xsd_string(ptr, "recordPacking", o,
444                                      &req->recordPacking))
445                     ;
446                 else if (match_xsd_string(ptr, "version", o,
447                                            &(*p)->srw_version))
448                     ;
449             }
450         }
451         else if (!strcmp(method->name, "explainResponse"))
452         {
453             Z_SRW_explainResponse *res;
454             xmlNodePtr ptr = method->children;
455
456             (*p)->which = Z_SRW_explain_response;
457             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
458             
459             for (; ptr; ptr = ptr->next)
460             {
461                 if (match_element(ptr, "record"))
462                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
463                 else if (match_xsd_string(ptr, "version", o,
464                                           &(*p)->srw_version))
465                     ;
466             }
467         }
468         else
469         {
470             *p = 0;
471             return -1;
472         }
473     }
474     else if (o->direction == ODR_ENCODE)
475     {
476         Z_SRW_PDU **p = handler_data;
477         xmlNsPtr ns_srw;
478         
479         if ((*p)->which == Z_SRW_searchRetrieve_request)
480         {
481             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
482             xmlNodePtr ptr = xmlNewChild(pptr, 0,
483                                          "searchRetrieveRequest", 0);
484             ns_srw = xmlNewNs(ptr, ns, "zs");
485             xmlSetNs(ptr, ns_srw);
486
487             if ((*p)->srw_version)
488                 add_xsd_string(ptr, "version", (*p)->srw_version);
489             switch(req->query_type)
490             {
491             case Z_SRW_query_type_cql:
492                 add_xsd_string(ptr, "query", req->query.cql);
493                 break;
494             case Z_SRW_query_type_xcql:
495                 add_xsd_string(ptr, "xQuery", req->query.xcql);
496                 break;
497             case Z_SRW_query_type_pqf:
498                 add_xsd_string(ptr, "pQuery", req->query.pqf);
499                 break;
500             }
501             switch(req->sort_type)
502             {
503             case Z_SRW_sort_type_none:
504                 break;
505             case Z_SRW_sort_type_sort:
506                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
507                 break;
508             case Z_SRW_sort_type_xSort:
509                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
510                 break;
511             }
512             add_xsd_integer(ptr, "startRecord", req->startRecord);
513             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
514             add_xsd_string(ptr, "recordSchema", req->recordSchema);
515             add_xsd_string(ptr, "recordPacking", req->recordPacking);
516             add_xsd_string(ptr, "database", req->database);
517         }
518         else if ((*p)->which == Z_SRW_searchRetrieve_response)
519         {
520             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
521             xmlNodePtr ptr = xmlNewChild(pptr, 0,
522                                          "searchRetrieveResponse", 0);
523             ns_srw = xmlNewNs(ptr, ns, "zs");
524             xmlSetNs(ptr, ns_srw);
525
526             if ((*p)->srw_version)
527                 add_xsd_string(ptr, "version", (*p)->srw_version);
528             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
529             add_xsd_string(ptr, "resultSetId", res->resultSetId);
530             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
531             if (res->num_records)
532             {
533                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
534                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
535                                 client_data, ns);
536             }
537             if (res->num_diagnostics)
538             {
539                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
540                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
541                                     &res->num_diagnostics, client_data, ns);
542             }
543             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
544         }
545         else if ((*p)->which == Z_SRW_explain_request)
546         {
547             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
548             ns_srw = xmlNewNs(ptr, ns, "zs");
549             xmlSetNs(ptr, ns_srw);
550
551             if ((*p)->srw_version)
552                 add_xsd_string(ptr, "version", (*p)->srw_version);
553         }
554         else if ((*p)->which == Z_SRW_explain_response)
555         {
556             Z_SRW_explainResponse *res = (*p)->u.explain_response;
557             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
558             ns_srw = xmlNewNs(ptr, ns, "zs");
559             xmlSetNs(ptr, ns_srw);
560
561             if ((*p)->srw_version)
562                 add_xsd_string(ptr, "version", (*p)->srw_version);
563             ptr = xmlNewChild(ptr, 0, "record", 0);
564             yaz_srw_record(o, ptr, &res->record, client_data, ns);
565         }
566         else
567             return -1;
568
569     }
570     return 0;
571 }
572
573 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
574 {
575     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
576
577     sr->srw_version = odr_strdup(o, "1.1");
578     sr->which = which;
579     switch(which)
580     {
581     case Z_SRW_searchRetrieve_request:
582         sr->u.request = (Z_SRW_searchRetrieveRequest *)
583             odr_malloc(o, sizeof(*sr->u.request));
584         sr->u.request->query_type = Z_SRW_query_type_cql;
585         sr->u.request->query.cql = 0;
586         sr->u.request->sort_type = Z_SRW_sort_type_none;
587         sr->u.request->sort.none = 0;
588         sr->u.request->startRecord = 0;
589         sr->u.request->maximumRecords = 0;
590         sr->u.request->recordSchema = 0;
591         sr->u.request->recordPacking = 0;
592         sr->u.request->database = 0;
593         break;
594     case Z_SRW_searchRetrieve_response:
595         sr->u.response = (Z_SRW_searchRetrieveResponse *)
596             odr_malloc(o, sizeof(*sr->u.response));
597         sr->u.response->numberOfRecords = 0;
598         sr->u.response->resultSetId = 0;
599         sr->u.response->resultSetIdleTime = 0;
600         sr->u.response->records = 0;
601         sr->u.response->num_records = 0;
602         sr->u.response->diagnostics = 0;
603         sr->u.response->num_diagnostics = 0;
604         sr->u.response->nextRecordPosition = 0;
605         break;
606     case Z_SRW_explain_request:
607         sr->u.explain_request = (Z_SRW_explainRequest *)
608             odr_malloc(o, sizeof(*sr->u.explain_request));
609         sr->u.explain_request->recordPacking = 0;
610         sr->u.explain_request->database = 0;
611         break;
612     case Z_SRW_explain_response:
613         sr->u.explain_response = (Z_SRW_explainResponse *)
614             odr_malloc(o, sizeof(*sr->u.explain_response));
615         sr->u.explain_response->record.recordData_buf = 0;
616         sr->u.explain_response->record.recordData_len = 0;
617         sr->u.explain_response->record.recordSchema = 0;
618         sr->u.explain_response->record.recordPosition = 0;
619         sr->u.explain_response->record.recordPacking = Z_SRW_recordPacking_string;
620     }
621     return sr;
622 }
623
624 #endif
625
626
627 static struct {
628     int code;
629     const char *msg;
630 } yaz_srw_codes [] = {
631 {1, "Permanent system error"}, 
632 {2, "System temporarily unavailable"}, 
633 {3, "Authentication error"}, 
634 /* Diagnostics Relating to CQL */
635 {10, "Illegal query"}, 
636 {11, "Unsupported query type (XCQL vs CQL)"}, 
637 {12, "Too many characters in query"}, 
638 {13, "Unbalanced or illegal use of parentheses"}, 
639 {14, "Unbalanced or illegal use of quotes"}, 
640 {15, "Illegal or unsupported context set"}, 
641 {16, "Illegal or unsupported index"}, 
642 {17, "Illegal or unsupported combination of index and context set"}, 
643 {18, "Illegal or unsupported combination of indexes"}, 
644 {19, "Illegal or unsupported relation"}, 
645 {20, "Illegal or unsupported relation modifier"}, 
646 {21, "Illegal or unsupported combination of relation modifers"}, 
647 {22, "Illegal or unsupported combination of relation and index"}, 
648 {23, "Too many characters in term"}, 
649 {24, "Illegal combination of relation and term"}, 
650 {25, "Special characters not quoted in term"}, 
651 {26, "Non special character escaped in term"}, 
652 {27, "Empty term unsupported"}, 
653 {28, "Masking character not supported"}, 
654 {29, "Masked words too short"}, 
655 {30, "Too many masking characters in term"}, 
656 {31, "Anchoring character not supported"}, 
657 {32, "Anchoring character in illegal or unsupported position"}, 
658 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
659 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
660 {35, "Terms only exclusion (stop) words"}, 
661 {36, "Term in invalid format for index or relation"}, 
662 {37, "Illegal or unsupported boolean operator"}, 
663 {38, "Too many boolean operators in query"}, 
664 {39, "Proximity not supported"}, 
665 {40, "Illegal or unsupported proximity relation"}, 
666 {41, "Illegal or unsupported proximity distance"}, 
667 {42, "Illegal or unsupported proximity unit"}, 
668 {43, "Illegal or unsupported proximity ordering"}, 
669 {44, "Illegal or unsupported combination of proximity modifiers"}, 
670 {45, "context set name (prefix) assigned to multiple identifiers"}, 
671 /* Diagnostics Relating to Result Sets */
672 {50, "Result sets not supported"}, 
673 {51, "Result set does not exist"}, 
674 {52, "Result set temporarily unavailable"}, 
675 {53, "Result sets only supported for retrieval"}, 
676 {54, "Retrieval may only occur from an existing result set"}, 
677 {55, "Combination of result sets with search terms not supported"}, 
678 {56, "Only combination of single result set with search terms supported"}, 
679 {57, "Result set created but no records available"}, 
680 {58, "Result set created with unpredictable partial results available"}, 
681 {59, "Result set created with valid partial results available"}, 
682 /* Diagnostics Relating to Records */
683 {60, "Too many records retrieved"}, 
684 {61, "First record position out of range"}, 
685 {62, "Negative number of records requested"}, 
686 {63, "System error in retrieving records"}, 
687 {64, "Record temporarily unavailable"}, 
688 {65, "Record does not exist"}, 
689 {66, "Unknown schema for retrieval"}, 
690 {67, "Record not available in this schema"}, 
691 {68, "Not authorised to send record"}, 
692 {69, "Not authorised to send record in this schema"}, 
693 {70, "Record too large to send"}, 
694 /* Diagnostics Relating to Sorting */
695 {80, "Sort not supported"}, 
696 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
697 {82, "Illegal or unsupported sort sequence"}, 
698 {83, "Too many records"}, 
699 {84, "Too many sort keys"}, 
700 {85, "Duplicate sort keys"}, 
701 {86, "Incompatible record formats"}, 
702 {87, "Unsupported schema for sort"}, 
703 {88, "Unsupported tag path for sort"}, 
704 {89, "Tag path illegal or unsupported for schema"}, 
705 {90, "Illegal or unsupported direction value"}, 
706 {91, "Illegal or unsupported case value"}, 
707 {92, "Illegal or unsupported missing value action"}, 
708 /* Diagnostics Relating to Explain */
709 {100, "Explain not supported"}, 
710 {101, "Explain request type not supported (SOAP vs GET)"}, 
711 {102, "Explain record temporarily unavailable"},
712 {0, 0}
713 };
714
715 const char *yaz_diag_srw_str (int code)
716 {
717     int i;
718     for (i = 0; yaz_srw_codes[i].code; i++)
719         if (yaz_srw_codes[i].code == code)
720             return yaz_srw_codes[i].msg;
721     return 0;
722 }
723
724
725 /* bib1:srw */
726 static int srw_bib1_map[] = {
727     1, 1,
728     2, 2,
729     3, 11,
730     4, 35,
731     5, 12,
732     6, 38,
733     7, 30,
734     8, 32,
735     9, 29,
736     10, 10,
737     11, 12,
738     11, 23,
739     12, 60,
740     13, 61,
741     13, 62,
742     14, 63,
743     14, 64,
744     14, 65,
745     15, 68,
746     15, 69,
747     16, 70,
748     17, 70,
749     18, 50,
750     19, 55,
751     20, 56, 
752     21, 52,
753     22, 50,
754     23, 1,  /* bad map */
755     24, 63, /* bad map */
756     25, 63, /* bad map */
757     26, 63, /* bad map */
758     27, 51,
759     28, 52,
760     29, 52,
761     30, 51,
762     31, 57,
763     32, 58,
764     33, 59,
765     100, 1, /* bad map */
766     101, 3,
767     102, 3,
768     103, 3,
769     104, 3,
770     105, 3, 
771     106, 66,
772     107, 11,
773     108, 10,
774     108, 13,
775     108, 14,
776     108, 25,
777     108, 26,
778     108, 27,
779     108, 45,
780         
781     109, 1,
782     110, 37,
783     111, 1,
784     112, 58,
785     113, 10,
786     114, 16,
787     115, 16,
788     116, 16,
789     117, 19,
790     118, 22,
791     119, 32,
792     119, 31,
793     120, 28,
794     121, 15,
795     122, 32,
796     123, 22,
797     123, 17,
798     123, 18,
799     124, 24,
800     125, 36,
801     126, 36, 
802     127, 36,
803     128, 51,
804     129, 39,
805     130, 43,
806     131, 40,
807     132, 42,
808     201, 44,
809     201, 33,
810     201, 34,
811     202, 41,
812     203, 43,
813     205, 1,  /* bad map */
814     206, 1,  /* bad map */
815     207, 89,
816     208, 1,  /* bad map */
817     209, 80,
818     210, 80,
819     210, 81,
820     211, 84,
821     212, 85,
822     213, 92,
823     214, 90,
824     215, 91,
825     216, 92,
826     217, 63,
827     218, 1,  /* bad map */
828     219, 1,  /* bad map */
829     220, 1,  /* bad map */
830     221, 1,  /* bad map */
831     222, 1,  /* bad map */
832     223, 1,  /* bad map */
833     224, 1,  /* bad map */
834     225, 1,  /* bad map */
835     226, 1,  /* bad map */
836     227, 66,
837     228, 1,  /* bad map */
838     229, 36,
839     230, 83,
840     231, 89,
841     232, 1,
842     233, 1, /* bad map */
843     234, 1, /* bad map */
844     235, 2,
845     236, 3, 
846     237, 82,
847     238, 67,
848     239, 66,
849     240, 1, /* bad map */
850     241, 1, /* bad map */
851     242, 70,
852     243, 1, /* bad map */
853     244, 66,
854     245, 10,
855     246, 10,
856     247, 10,
857     1001, 1, /* bad map */
858     1002, 1, /* bad map */
859     1003, 1, /* bad map */
860     1004, 1, /* bad map */
861     1005, 1, /* bad map */
862     1006, 1, /* bad map */
863     1007, 100,
864     1008, 1, 
865     1009, 1,
866     1010, 3,
867     1011, 3,
868     1012, 3,
869     1013, 3,
870     1014, 3,
871     1015, 3,
872     1015, 3,
873     1016, 3,
874     1017, 3,
875     1018, 2,
876     1019, 2,
877     1020, 2,
878     1021, 3,
879     1022, 3,
880     1023, 3,
881     1024, 16,
882     1025, 3,
883     1026, 64,
884     1027, 1,
885     1028, 65,
886     1029, 1,
887     1040, 1,
888     /* 1041-1065 */
889     1066, 66,
890     1066, 67,
891     0
892 };
893
894 int yaz_diag_bib1_to_srw (int code)
895 {
896     const int *p = srw_bib1_map;
897     while (*p)
898     {
899         if (code == p[0])
900             return p[1];
901         p += 2;
902     }
903     return 1;
904 }
905
906 int yaz_diag_srw_to_bib1(int code)
907 {
908     const int *p = srw_bib1_map;
909     while (*p)
910     {
911         if (code == p[1])
912             return p[0];
913         p += 2;
914     }
915     return 1;
916 }
917