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