cd8b48cae866b6ed2d15a2a54734b515d0a63575
[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.4 2003-12-20 22:40:46 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         sr->u.explain_response->record.recordSchema = 0;
617         sr->u.explain_response->record.recordPosition = 0;
618         sr->u.explain_response->record.recordPacking = Z_SRW_recordPacking_string;
619     }
620     return sr;
621 }
622
623 #endif
624
625
626 static struct {
627     int code;
628     const char *msg;
629 } yaz_srw_codes [] = {
630 {1, "Permanent system error"}, 
631 {2, "System temporarily unavailable"}, 
632 {3, "Authentication error"}, 
633 /* Diagnostics Relating to CQL */
634 {10, "Illegal query"}, 
635 {11, "Unsupported query type (XCQL vs CQL)"}, 
636 {12, "Too many characters in query"}, 
637 {13, "Unbalanced or illegal use of parentheses"}, 
638 {14, "Unbalanced or illegal use of quotes"}, 
639 {15, "Illegal or unsupported context set"}, 
640 {16, "Illegal or unsupported index"}, 
641 {17, "Illegal or unsupported combination of index and context set"}, 
642 {18, "Illegal or unsupported combination of indexes"}, 
643 {19, "Illegal or unsupported relation"}, 
644 {20, "Illegal or unsupported relation modifier"}, 
645 {21, "Illegal or unsupported combination of relation modifers"}, 
646 {22, "Illegal or unsupported combination of relation and index"}, 
647 {23, "Too many characters in term"}, 
648 {24, "Illegal combination of relation and term"}, 
649 {25, "Special characters not quoted in term"}, 
650 {26, "Non special character escaped in term"}, 
651 {27, "Empty term unsupported"}, 
652 {28, "Masking character not supported"}, 
653 {29, "Masked words too short"}, 
654 {30, "Too many masking characters in term"}, 
655 {31, "Anchoring character not supported"}, 
656 {32, "Anchoring character in illegal or unsupported position"}, 
657 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
658 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
659 {35, "Terms only exclusion (stop) words"}, 
660 {36, "Term in invalid format for index or relation"}, 
661 {37, "Illegal or unsupported boolean operator"}, 
662 {38, "Too many boolean operators in query"}, 
663 {39, "Proximity not supported"}, 
664 {40, "Illegal or unsupported proximity relation"}, 
665 {41, "Illegal or unsupported proximity distance"}, 
666 {42, "Illegal or unsupported proximity unit"}, 
667 {43, "Illegal or unsupported proximity ordering"}, 
668 {44, "Illegal or unsupported combination of proximity modifiers"}, 
669 {45, "context set name (prefix) assigned to multiple identifiers"}, 
670 /* Diagnostics Relating to Result Sets */
671 {50, "Result sets not supported"}, 
672 {51, "Result set does not exist"}, 
673 {52, "Result set temporarily unavailable"}, 
674 {53, "Result sets only supported for retrieval"}, 
675 {54, "Retrieval may only occur from an existing result set"}, 
676 {55, "Combination of result sets with search terms not supported"}, 
677 {56, "Only combination of single result set with search terms supported"}, 
678 {57, "Result set created but no records available"}, 
679 {58, "Result set created with unpredictable partial results available"}, 
680 {59, "Result set created with valid partial results available"}, 
681 /* Diagnostics Relating to Records */
682 {60, "Too many records retrieved"}, 
683 {61, "First record position out of range"}, 
684 {62, "Negative number of records requested"}, 
685 {63, "System error in retrieving records"}, 
686 {64, "Record temporarily unavailable"}, 
687 {65, "Record does not exist"}, 
688 {66, "Unknown schema for retrieval"}, 
689 {67, "Record not available in this schema"}, 
690 {68, "Not authorised to send record"}, 
691 {69, "Not authorised to send record in this schema"}, 
692 {70, "Record too large to send"}, 
693 /* Diagnostics Relating to Sorting */
694 {80, "Sort not supported"}, 
695 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
696 {82, "Illegal or unsupported sort sequence"}, 
697 {83, "Too many records"}, 
698 {84, "Too many sort keys"}, 
699 {85, "Duplicate sort keys"}, 
700 {86, "Incompatible record formats"}, 
701 {87, "Unsupported schema for sort"}, 
702 {88, "Unsupported tag path for sort"}, 
703 {89, "Tag path illegal or unsupported for schema"}, 
704 {90, "Illegal or unsupported direction value"}, 
705 {91, "Illegal or unsupported case value"}, 
706 {92, "Illegal or unsupported missing value action"}, 
707 /* Diagnostics Relating to Explain */
708 {100, "Explain not supported"}, 
709 {101, "Explain request type not supported (SOAP vs GET)"}, 
710 {102, "Explain record temporarily unavailable"},
711 {0, 0}
712 };
713
714 const char *yaz_diag_srw_str (int code)
715 {
716     int i;
717     for (i = 0; yaz_srw_codes[i].code; i++)
718         if (yaz_srw_codes[i].code == code)
719             return yaz_srw_codes[i].msg;
720     return 0;
721 }
722
723
724 /* bib1:srw */
725 static int srw_bib1_map[] = {
726     1, 1,
727     2, 2,
728     3, 11,
729     4, 35,
730     5, 12,
731     6, 38,
732     7, 30,
733     8, 32,
734     9, 29,
735     10, 10,
736     11, 12,
737     11, 23,
738     12, 60,
739     13, 61,
740     13, 62,
741     14, 63,
742     14, 64,
743     14, 65,
744     15, 68,
745     15, 69,
746     16, 70,
747     17, 70,
748     18, 50,
749     19, 55,
750     20, 56, 
751     21, 52,
752     22, 50,
753     23, 1,  /* bad map */
754     24, 63, /* bad map */
755     25, 63, /* bad map */
756     26, 63, /* bad map */
757     27, 51,
758     28, 52,
759     29, 52,
760     30, 51,
761     31, 57,
762     32, 58,
763     33, 59,
764     100, 1, /* bad map */
765     101, 3,
766     102, 3,
767     103, 3,
768     104, 3,
769     105, 3, 
770     106, 66,
771     107, 11,
772     108, 10,
773     108, 13,
774     108, 14,
775     108, 25,
776     108, 26,
777     108, 27,
778     108, 45,
779         
780     109, 1,
781     110, 37,
782     111, 1,
783     112, 58,
784     113, 10,
785     114, 16,
786     115, 16,
787     116, 16,
788     117, 19,
789     118, 22,
790     119, 32,
791     119, 31,
792     120, 28,
793     121, 15,
794     122, 32,
795     123, 22,
796     123, 17,
797     123, 18,
798     124, 24,
799     125, 36,
800     126, 36, 
801     127, 36,
802     128, 51,
803     129, 39,
804     130, 43,
805     131, 40,
806     132, 42,
807     201, 44,
808     201, 33,
809     201, 34,
810     202, 41,
811     203, 43,
812     205, 1,  /* bad map */
813     206, 1,  /* bad map */
814     207, 89,
815     208, 1,  /* bad map */
816     209, 80,
817     210, 80,
818     210, 81,
819     211, 84,
820     212, 85,
821     213, 92,
822     214, 90,
823     215, 91,
824     216, 92,
825     217, 63,
826     218, 1,  /* bad map */
827     219, 1,  /* bad map */
828     220, 1,  /* bad map */
829     221, 1,  /* bad map */
830     222, 1,  /* bad map */
831     223, 1,  /* bad map */
832     224, 1,  /* bad map */
833     225, 1,  /* bad map */
834     226, 1,  /* bad map */
835     227, 66,
836     228, 1,  /* bad map */
837     229, 36,
838     230, 83,
839     231, 89,
840     232, 1,
841     233, 1, /* bad map */
842     234, 1, /* bad map */
843     235, 2,
844     236, 3, 
845     237, 82,
846     238, 67,
847     239, 66,
848     240, 1, /* bad map */
849     241, 1, /* bad map */
850     242, 70,
851     243, 1, /* bad map */
852     244, 66,
853     245, 10,
854     246, 10,
855     247, 10,
856     1001, 1, /* bad map */
857     1002, 1, /* bad map */
858     1003, 1, /* bad map */
859     1004, 1, /* bad map */
860     1005, 1, /* bad map */
861     1006, 1, /* bad map */
862     1007, 100,
863     1008, 1, 
864     1009, 1,
865     1010, 3,
866     1011, 3,
867     1012, 3,
868     1013, 3,
869     1014, 3,
870     1015, 3,
871     1015, 3,
872     1016, 3,
873     1017, 3,
874     1018, 2,
875     1019, 2,
876     1020, 2,
877     1021, 3,
878     1022, 3,
879     1023, 3,
880     1024, 16,
881     1025, 3,
882     1026, 64,
883     1027, 1,
884     1028, 65,
885     1029, 1,
886     1040, 1,
887     /* 1041-1065 */
888     1066, 66,
889     1066, 67,
890     0
891 };
892
893 int yaz_diag_bib1_to_srw (int code)
894 {
895     const int *p = srw_bib1_map;
896     while (*p)
897     {
898         if (code == p[0])
899             return p[1];
900         p += 2;
901     }
902     return 1;
903 }
904
905 int yaz_diag_srw_to_bib1(int code)
906 {
907     const int *p = srw_bib1_map;
908     while (*p)
909     {
910         if (code == p[1])
911             return p[0];
912         p += 2;
913     }
914     return 1;
915 }
916