SRW/SRU 1.1
[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.3 2003-12-20 00:51:19 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             for (; ptr; ptr = ptr->next)
441             {
442                 if (match_xsd_string(ptr, "recordPacking", o,
443                                      &req->recordPacking))
444                     ;
445                 else if (match_xsd_string(ptr, "version", o,
446                                            &(*p)->srw_version))
447                     ;
448             }
449         }
450         else if (!strcmp(method->name, "explainResponse"))
451         {
452             Z_SRW_explainResponse *res;
453             xmlNodePtr ptr = method->children;
454
455             (*p)->which = Z_SRW_explain_response;
456             res = (*p)->u.explain_response = odr_malloc(o, sizeof(*res));
457             
458             for (; ptr; ptr = ptr->next)
459             {
460                 if (match_element(ptr, "record"))
461                     yaz_srw_record(o, ptr, &res->record, client_data, ns);
462                 else if (match_xsd_string(ptr, "version", o,
463                                           &(*p)->srw_version))
464                     ;
465             }
466         }
467         else
468         {
469             *p = 0;
470             return -1;
471         }
472     }
473     else if (o->direction == ODR_ENCODE)
474     {
475         Z_SRW_PDU **p = handler_data;
476         xmlNsPtr ns_srw;
477         
478         if ((*p)->which == Z_SRW_searchRetrieve_request)
479         {
480             Z_SRW_searchRetrieveRequest *req = (*p)->u.request;
481             xmlNodePtr ptr = xmlNewChild(pptr, 0,
482                                          "searchRetrieveRequest", 0);
483             ns_srw = xmlNewNs(ptr, ns, "zs");
484             xmlSetNs(ptr, ns_srw);
485
486             if ((*p)->srw_version)
487                 add_xsd_string(ptr, "version", (*p)->srw_version);
488             switch(req->query_type)
489             {
490             case Z_SRW_query_type_cql:
491                 add_xsd_string(ptr, "query", req->query.cql);
492                 break;
493             case Z_SRW_query_type_xcql:
494                 add_xsd_string(ptr, "xQuery", req->query.xcql);
495                 break;
496             case Z_SRW_query_type_pqf:
497                 add_xsd_string(ptr, "pQuery", req->query.pqf);
498                 break;
499             }
500             switch(req->sort_type)
501             {
502             case Z_SRW_sort_type_none:
503                 break;
504             case Z_SRW_sort_type_sort:
505                 add_xsd_string(ptr, "sortKeys", req->sort.sortKeys);
506                 break;
507             case Z_SRW_sort_type_xSort:
508                 add_xsd_string(ptr, "xSortKeys", req->sort.xSortKeys);
509                 break;
510             }
511             add_xsd_integer(ptr, "startRecord", req->startRecord);
512             add_xsd_integer(ptr, "maximumRecords", req->maximumRecords);
513             add_xsd_string(ptr, "recordSchema", req->recordSchema);
514             add_xsd_string(ptr, "recordPacking", req->recordPacking);
515             add_xsd_string(ptr, "database", req->database);
516         }
517         else if ((*p)->which == Z_SRW_searchRetrieve_response)
518         {
519             Z_SRW_searchRetrieveResponse *res = (*p)->u.response;
520             xmlNodePtr ptr = xmlNewChild(pptr, 0,
521                                          "searchRetrieveResponse", 0);
522             ns_srw = xmlNewNs(ptr, ns, "zs");
523             xmlSetNs(ptr, ns_srw);
524
525             if ((*p)->srw_version)
526                 add_xsd_string(ptr, "version", (*p)->srw_version);
527             add_xsd_integer(ptr, "numberOfRecords", res->numberOfRecords);
528             add_xsd_string(ptr, "resultSetId", res->resultSetId);
529             add_xsd_integer(ptr, "resultSetIdleTime", res->resultSetIdleTime);
530             if (res->num_records)
531             {
532                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "records", 0);
533                 yaz_srw_records(o, rptr, &res->records, &res->num_records,
534                                 client_data, ns);
535             }
536             if (res->num_diagnostics)
537             {
538                 xmlNodePtr rptr = xmlNewChild(ptr, 0, "diagnostics", 0);
539                 yaz_srw_diagnostics(o, rptr, &res->diagnostics,
540                                     &res->num_diagnostics, client_data, ns);
541             }
542             add_xsd_integer(ptr, "nextRecordPosition", res->nextRecordPosition);
543         }
544         else if ((*p)->which == Z_SRW_explain_request)
545         {
546             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainRequest", 0);
547             ns_srw = xmlNewNs(ptr, ns, "zs");
548             xmlSetNs(ptr, ns_srw);
549
550             if ((*p)->srw_version)
551                 add_xsd_string(ptr, "version", (*p)->srw_version);
552         }
553         else if ((*p)->which == Z_SRW_explain_response)
554         {
555             Z_SRW_explainResponse *res = (*p)->u.explain_response;
556             xmlNodePtr ptr = xmlNewChild(pptr, 0, "explainResponse", 0);
557             ns_srw = xmlNewNs(ptr, ns, "zs");
558             xmlSetNs(ptr, ns_srw);
559
560             if ((*p)->srw_version)
561                 add_xsd_string(ptr, "version", (*p)->srw_version);
562             ptr = xmlNewChild(ptr, 0, "record", 0);
563             yaz_srw_record(o, ptr, &res->record, client_data, ns);
564         }
565         else
566             return -1;
567
568     }
569     return 0;
570 }
571
572 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
573 {
574     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
575
576     sr->srw_version = odr_strdup(o, "1.1");
577     sr->which = which;
578     switch(which)
579     {
580     case Z_SRW_searchRetrieve_request:
581         sr->u.request = (Z_SRW_searchRetrieveRequest *)
582             odr_malloc(o, sizeof(*sr->u.request));
583         sr->u.request->query_type = Z_SRW_query_type_cql;
584         sr->u.request->query.cql = 0;
585         sr->u.request->sort_type = Z_SRW_sort_type_none;
586         sr->u.request->sort.none = 0;
587         sr->u.request->startRecord = 0;
588         sr->u.request->maximumRecords = 0;
589         sr->u.request->recordSchema = 0;
590         sr->u.request->recordPacking = 0;
591         sr->u.request->database = 0;
592         break;
593     case Z_SRW_searchRetrieve_response:
594         sr->u.response = (Z_SRW_searchRetrieveResponse *)
595             odr_malloc(o, sizeof(*sr->u.response));
596         sr->u.response->numberOfRecords = 0;
597         sr->u.response->resultSetId = 0;
598         sr->u.response->resultSetIdleTime = 0;
599         sr->u.response->records = 0;
600         sr->u.response->num_records = 0;
601         sr->u.response->diagnostics = 0;
602         sr->u.response->num_diagnostics = 0;
603         sr->u.response->nextRecordPosition = 0;
604         break;
605     case Z_SRW_explain_request:
606         sr->u.explain_request = (Z_SRW_explainRequest *)
607             odr_malloc(o, sizeof(*sr->u.explain_request));
608         sr->u.explain_request->recordPacking = 0;
609         sr->u.explain_request->database = 0;
610         break;
611     case Z_SRW_explain_response:
612         sr->u.explain_response = (Z_SRW_explainResponse *)
613             odr_malloc(o, sizeof(*sr->u.explain_response));
614         sr->u.explain_response->record.recordData_buf = 0;
615         sr->u.explain_response->record.recordData_len = 0;
616     }
617     return sr;
618 }
619
620 #endif
621
622
623 static struct {
624     int code;
625     const char *msg;
626 } yaz_srw_codes [] = {
627 {1, "Permanent system error"}, 
628 {2, "System temporarily unavailable"}, 
629 {3, "Authentication error"}, 
630 /* Diagnostics Relating to CQL */
631 {10, "Illegal query"}, 
632 {11, "Unsupported query type (XCQL vs CQL)"}, 
633 {12, "Too many characters in query"}, 
634 {13, "Unbalanced or illegal use of parentheses"}, 
635 {14, "Unbalanced or illegal use of quotes"}, 
636 {15, "Illegal or unsupported context set"}, 
637 {16, "Illegal or unsupported index"}, 
638 {17, "Illegal or unsupported combination of index and context set"}, 
639 {18, "Illegal or unsupported combination of indexes"}, 
640 {19, "Illegal or unsupported relation"}, 
641 {20, "Illegal or unsupported relation modifier"}, 
642 {21, "Illegal or unsupported combination of relation modifers"}, 
643 {22, "Illegal or unsupported combination of relation and index"}, 
644 {23, "Too many characters in term"}, 
645 {24, "Illegal combination of relation and term"}, 
646 {25, "Special characters not quoted in term"}, 
647 {26, "Non special character escaped in term"}, 
648 {27, "Empty term unsupported"}, 
649 {28, "Masking character not supported"}, 
650 {29, "Masked words too short"}, 
651 {30, "Too many masking characters in term"}, 
652 {31, "Anchoring character not supported"}, 
653 {32, "Anchoring character in illegal or unsupported position"}, 
654 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
655 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
656 {35, "Terms only exclusion (stop) words"}, 
657 {36, "Term in invalid format for index or relation"}, 
658 {37, "Illegal or unsupported boolean operator"}, 
659 {38, "Too many boolean operators in query"}, 
660 {39, "Proximity not supported"}, 
661 {40, "Illegal or unsupported proximity relation"}, 
662 {41, "Illegal or unsupported proximity distance"}, 
663 {42, "Illegal or unsupported proximity unit"}, 
664 {43, "Illegal or unsupported proximity ordering"}, 
665 {44, "Illegal or unsupported combination of proximity modifiers"}, 
666 {45, "context set name (prefix) assigned to multiple identifiers"}, 
667 /* Diagnostics Relating to Result Sets */
668 {50, "Result sets not supported"}, 
669 {51, "Result set does not exist"}, 
670 {52, "Result set temporarily unavailable"}, 
671 {53, "Result sets only supported for retrieval"}, 
672 {54, "Retrieval may only occur from an existing result set"}, 
673 {55, "Combination of result sets with search terms not supported"}, 
674 {56, "Only combination of single result set with search terms supported"}, 
675 {57, "Result set created but no records available"}, 
676 {58, "Result set created with unpredictable partial results available"}, 
677 {59, "Result set created with valid partial results available"}, 
678 /* Diagnostics Relating to Records */
679 {60, "Too many records retrieved"}, 
680 {61, "First record position out of range"}, 
681 {62, "Negative number of records requested"}, 
682 {63, "System error in retrieving records"}, 
683 {64, "Record temporarily unavailable"}, 
684 {65, "Record does not exist"}, 
685 {66, "Unknown schema for retrieval"}, 
686 {67, "Record not available in this schema"}, 
687 {68, "Not authorised to send record"}, 
688 {69, "Not authorised to send record in this schema"}, 
689 {70, "Record too large to send"}, 
690 /* Diagnostics Relating to Sorting */
691 {80, "Sort not supported"}, 
692 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
693 {82, "Illegal or unsupported sort sequence"}, 
694 {83, "Too many records"}, 
695 {84, "Too many sort keys"}, 
696 {85, "Duplicate sort keys"}, 
697 {86, "Incompatible record formats"}, 
698 {87, "Unsupported schema for sort"}, 
699 {88, "Unsupported tag path for sort"}, 
700 {89, "Tag path illegal or unsupported for schema"}, 
701 {90, "Illegal or unsupported direction value"}, 
702 {91, "Illegal or unsupported case value"}, 
703 {92, "Illegal or unsupported missing value action"}, 
704 /* Diagnostics Relating to Explain */
705 {100, "Explain not supported"}, 
706 {101, "Explain request type not supported (SOAP vs GET)"}, 
707 {102, "Explain record temporarily unavailable"},
708 {0, 0}
709 };
710
711 const char *yaz_diag_srw_str (int code)
712 {
713     int i;
714     for (i = 0; yaz_srw_codes[i].code; i++)
715         if (yaz_srw_codes[i].code == code)
716             return yaz_srw_codes[i].msg;
717     return 0;
718 }
719
720
721 /* bib1:srw */
722 static int srw_bib1_map[] = {
723     1, 1,
724     2, 2,
725     3, 11,
726     4, 35,
727     5, 12,
728     6, 38,
729     7, 30,
730     8, 32,
731     9, 29,
732     10, 10,
733     11, 12,
734     11, 23,
735     12, 60,
736     13, 61,
737     13, 62,
738     14, 63,
739     14, 64,
740     14, 65,
741     15, 68,
742     15, 69,
743     16, 70,
744     17, 70,
745     18, 50,
746     19, 55,
747     20, 56, 
748     21, 52,
749     22, 50,
750     23, 1,  /* bad map */
751     24, 63, /* bad map */
752     25, 63, /* bad map */
753     26, 63, /* bad map */
754     27, 51,
755     28, 52,
756     29, 52,
757     30, 51,
758     31, 57,
759     32, 58,
760     33, 59,
761     100, 1, /* bad map */
762     101, 3,
763     102, 3,
764     103, 3,
765     104, 3,
766     105, 3, 
767     106, 66,
768     107, 11,
769     108, 10,
770     108, 13,
771     108, 14,
772     108, 25,
773     108, 26,
774     108, 27,
775     108, 45,
776         
777     109, 1,
778     110, 37,
779     111, 1,
780     112, 58,
781     113, 10,
782     114, 16,
783     115, 16,
784     116, 16,
785     117, 19,
786     118, 22,
787     119, 32,
788     119, 31,
789     120, 28,
790     121, 15,
791     122, 32,
792     123, 22,
793     123, 17,
794     123, 18,
795     124, 24,
796     125, 36,
797     126, 36, 
798     127, 36,
799     128, 51,
800     129, 39,
801     130, 43,
802     131, 40,
803     132, 42,
804     201, 44,
805     201, 33,
806     201, 34,
807     202, 41,
808     203, 43,
809     205, 1,  /* bad map */
810     206, 1,  /* bad map */
811     207, 89,
812     208, 1,  /* bad map */
813     209, 80,
814     210, 80,
815     210, 81,
816     211, 84,
817     212, 85,
818     213, 92,
819     214, 90,
820     215, 91,
821     216, 92,
822     217, 63,
823     218, 1,  /* bad map */
824     219, 1,  /* bad map */
825     220, 1,  /* bad map */
826     221, 1,  /* bad map */
827     222, 1,  /* bad map */
828     223, 1,  /* bad map */
829     224, 1,  /* bad map */
830     225, 1,  /* bad map */
831     226, 1,  /* bad map */
832     227, 66,
833     228, 1,  /* bad map */
834     229, 36,
835     230, 83,
836     231, 89,
837     232, 1,
838     233, 1, /* bad map */
839     234, 1, /* bad map */
840     235, 2,
841     236, 3, 
842     237, 82,
843     238, 67,
844     239, 66,
845     240, 1, /* bad map */
846     241, 1, /* bad map */
847     242, 70,
848     243, 1, /* bad map */
849     244, 66,
850     245, 10,
851     246, 10,
852     247, 10,
853     1001, 1, /* bad map */
854     1002, 1, /* bad map */
855     1003, 1, /* bad map */
856     1004, 1, /* bad map */
857     1005, 1, /* bad map */
858     1006, 1, /* bad map */
859     1007, 100,
860     1008, 1, 
861     1009, 1,
862     1010, 3,
863     1011, 3,
864     1012, 3,
865     1013, 3,
866     1014, 3,
867     1015, 3,
868     1015, 3,
869     1016, 3,
870     1017, 3,
871     1018, 2,
872     1019, 2,
873     1020, 2,
874     1021, 3,
875     1022, 3,
876     1023, 3,
877     1024, 16,
878     1025, 3,
879     1026, 64,
880     1027, 1,
881     1028, 65,
882     1029, 1,
883     1040, 1,
884     /* 1041-1065 */
885     1066, 66,
886     1066, 67,
887     0
888 };
889
890 int yaz_diag_bib1_to_srw (int code)
891 {
892     const int *p = srw_bib1_map;
893     while (*p)
894     {
895         if (code == p[0])
896             return p[1];
897         p += 2;
898     }
899     return 1;
900 }
901
902 int yaz_diag_srw_to_bib1(int code)
903 {
904     const int *p = srw_bib1_map;
905     while (*p)
906     {
907         if (code == p[1])
908             return p[0];
909         p += 2;
910     }
911     return 1;
912 }
913