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