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